home *** CD-ROM | disk | FTP | other *** search
/ Aminet 48 / Aminet 48 (2002)(GTI - Schatztruhe)[!][Apr 2002].iso / Aminet / text / edit / vim60src.lha / Vim / vim60 / src / buffer.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-09-19  |  104.8 KB  |  4,541 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  * See README.txt for an overview of the Vim source code.
  8.  */
  9.  
  10. /*
  11.  * buffer.c: functions for dealing with the buffer structure
  12.  */
  13.  
  14. /*
  15.  * The buffer list is a double linked list of all buffers.
  16.  * Each buffer can be in one of these states:
  17.  * never loaded: BF_NEVERLOADED is set, only the file name is valid
  18.  *   not loaded: b_ml.ml_mfp == NULL, no memfile allocated
  19.  *     hidden: b_nwindows == 0, loaded but not displayed in a window
  20.  *     normal: loaded and displayed in a window
  21.  *
  22.  * Instead of storing file names all over the place, each file name is
  23.  * stored in the buffer list. It can be referenced by a number.
  24.  *
  25.  * The current implementation remembers all file names ever used.
  26.  */
  27.  
  28.  
  29. #include "vim.h"
  30.  
  31. #if defined(FEAT_CMDL_COMPL) || defined(FEAT_LISTCMDS) || defined(FEAT_EVAL) || defined(FEAT_PERL)
  32. static char_u    *buflist_match __ARGS((regprog_T *prog, buf_T *buf));
  33. # define HAVE_BUFLIST_MATCH
  34. static char_u    *fname_match __ARGS((regprog_T *prog, char_u *name));
  35. #endif
  36. static void    buflist_setfpos __ARGS((buf_T *buf, win_T *win, linenr_T lnum, colnr_T col, int copy_options));
  37. static wininfo_T *find_wininfo __ARGS((buf_T *buf));
  38. #ifdef UNIX
  39. static buf_T    *buflist_findname_stat __ARGS((char_u *ffname, struct stat *st));
  40. static int    otherfile_buf __ARGS((buf_T *buf, char_u *ffname, struct stat *stp));
  41. static int    buf_same_ino __ARGS((buf_T *buf, struct stat *stp));
  42. #else
  43. static int    otherfile_buf __ARGS((buf_T *buf, char_u *ffname));
  44. #endif
  45. #ifdef FEAT_TITLE
  46. static int    ti_change __ARGS((char_u *str, char_u **last));
  47. #endif
  48. static void    free_buffer __ARGS((buf_T *));
  49. static void    free_buffer_stuff __ARGS((buf_T *));
  50. static void    clear_wininfo __ARGS((buf_T *buf));
  51.  
  52. #ifdef UNIX
  53. # define dev_T dev_t
  54. #else
  55. # define dev_T unsigned
  56. #endif
  57.  
  58. /*
  59.  * Open current buffer, that is: open the memfile and read the file into memory
  60.  * return FAIL for failure, OK otherwise
  61.  */
  62.     int
  63. open_buffer(read_stdin, eap)
  64.     int        read_stdin;        /* read file from stdin */
  65.     exarg_T    *eap;            /* for forced 'ff' and 'fenc' or NULL */
  66. {
  67.     int        retval = OK;
  68. #ifdef FEAT_AUTOCMD
  69.     buf_T    *old_curbuf;
  70. #endif
  71.  
  72.     /*
  73.      * The 'readonly' flag is only set when BF_NEVERLOADED is being reset.
  74.      * When re-entering the same buffer, it should not change, because the
  75.      * user may have reset the flag by hand.
  76.      */
  77.     if (readonlymode && curbuf->b_ffname != NULL
  78.                     && (curbuf->b_flags & BF_NEVERLOADED))
  79.     curbuf->b_p_ro = TRUE;
  80.  
  81.     if (ml_open() == FAIL)
  82.     {
  83.     /*
  84.      * There MUST be a memfile, otherwise we can't do anything
  85.      * If we can't create one for the current buffer, take another buffer
  86.      */
  87.     close_buffer(NULL, curbuf, 0);
  88.     for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next)
  89.         if (curbuf->b_ml.ml_mfp != NULL)
  90.         break;
  91.     /*
  92.      * if there is no memfile at all, exit
  93.      * This is OK, since there are no changes to loose.
  94.      */
  95.     if (curbuf == NULL)
  96.     {
  97.         EMSG(_("E82: Cannot allocate any buffer, exiting..."));
  98.         getout(2);
  99.     }
  100.     EMSG(_("E83: Cannot allocate buffer, using other one..."));
  101.     enter_buffer(curbuf);
  102.     return FAIL;
  103.     }
  104.  
  105. #ifdef FEAT_AUTOCMD
  106.     /* The autocommands in readfile() may change the buffer, but only AFTER
  107.      * reading the file. */
  108.     old_curbuf = curbuf;
  109.     modified_was_set = FALSE;
  110. #endif
  111.  
  112.     /* mark cursor position as being invalid */
  113.     changed_line_abv_curs();
  114.  
  115.     if (curbuf->b_ffname != NULL)
  116.     {
  117.     retval = readfile(curbuf->b_ffname, curbuf->b_fname,
  118.           (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, eap, READ_NEW);
  119.     /* Help buffer is filtered. */
  120.     if (curbuf->b_help)
  121.         fix_help_buffer();
  122.     }
  123.     else if (read_stdin)
  124.     {
  125.     int        save_bin = curbuf->b_p_bin;
  126.     linenr_T    line_count;
  127.  
  128.     /*
  129.      * First read the text in binary mode into the buffer.
  130.      * Then read from that same buffer and append at the end.  This makes
  131.      * it possible to retry when 'fileformat' or 'fileencoding' was
  132.      * guessed wrong.
  133.      */
  134.     curbuf->b_p_bin = TRUE;
  135.     retval = readfile(NULL, NULL, (linenr_T)0,
  136.           (linenr_T)0, (linenr_T)MAXLNUM, eap, READ_NEW + READ_STDIN);
  137.     curbuf->b_p_bin = save_bin;
  138.     if (retval == OK)
  139.     {
  140.         line_count = curbuf->b_ml.ml_line_count;
  141.         retval = readfile(NULL, NULL, (linenr_T)line_count,
  142.                 (linenr_T)0, (linenr_T)MAXLNUM, eap, READ_BUFFER);
  143.         if (retval == OK)
  144.         {
  145.         /* Delete the binary lines. */
  146.         while (--line_count >= 0)
  147.             ml_delete((linenr_T)1, FALSE);
  148.         }
  149.         else
  150.         {
  151.         /* Delete the converted lines. */
  152.         while (curbuf->b_ml.ml_line_count > line_count)
  153.             ml_delete(line_count, FALSE);
  154.         }
  155.         /* Put the cursor on the first line. */
  156.         curwin->w_cursor.lnum = 1;
  157.         curwin->w_cursor.col = 0;
  158. #ifdef FEAT_AUTOCMD
  159.         apply_autocmds(EVENT_STDINREADPOST, NULL, NULL, FALSE, curbuf);
  160. #endif
  161.     }
  162.     }
  163.  
  164.     /* if first time loading this buffer, init b_chartab[] */
  165.     if (curbuf->b_flags & BF_NEVERLOADED)
  166.     (void)buf_init_chartab(curbuf, FALSE);
  167.  
  168.     /*
  169.      * Set/reset the Changed flag first, autocmds may change the buffer.
  170.      * Apply the automatic commands, before processing the modelines.
  171.      * So the modelines have priority over auto commands.
  172.      */
  173.     /* When reading stdin, the buffer contents always needs writing, so set
  174.      * the changed flag.  Unless in readonly mode: "ls | gview -".
  175.      * When interrupted and 'cpoptions' contains 'i' set changed flag. */
  176.     if ((read_stdin && !readonlymode && !bufempty())
  177. #ifdef FEAT_AUTOCMD
  178.         || modified_was_set    /* ":set modified" used in autocmd */
  179. #endif
  180.         || (got_int && vim_strchr(p_cpo, CPO_INTMOD) != NULL))
  181.     changed();
  182.     else if (retval != FAIL)
  183.     unchanged(curbuf, FALSE);
  184.     save_file_ff(curbuf);        /* keep this fileformat */
  185.  
  186.     /* require "!" to overwrite the file, because it wasn't read completely */
  187.     if (got_int)
  188.     curbuf->b_flags |= BF_READERR;
  189.  
  190. #ifdef FEAT_AUTOCMD
  191.     /* need to set w_topline, unless some autocommand already did that. */
  192.     if (!(curwin->w_valid & VALID_TOPLINE))
  193.     {
  194.     curwin->w_topline = 1;
  195. # ifdef FEAT_DIFF
  196.     curwin->w_topfill = 0;
  197. # endif
  198.     }
  199.     apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
  200. #endif
  201.  
  202.     if (retval != FAIL)
  203.     {
  204. #ifdef FEAT_AUTOCMD
  205.     /*
  206.      * The autocommands may have changed the current buffer.  Apply the
  207.      * modelines to the correct buffer, if it still exists and is loaded.
  208.      */
  209.     if (buf_valid(old_curbuf) && old_curbuf->b_ml.ml_mfp != NULL)
  210.     {
  211.         aco_save_T    aco;
  212.  
  213.         /* Go to the buffer that was opened. */
  214.         aucmd_prepbuf(&aco, old_curbuf);
  215. #endif
  216.         do_modelines();
  217.         curbuf->b_flags &= ~(BF_CHECK_RO | BF_NEVERLOADED);
  218.  
  219. #ifdef FEAT_AUTOCMD
  220.         apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf);
  221.  
  222.         /* restore curwin/curbuf and a few other things */
  223.         aucmd_restbuf(&aco);
  224.     }
  225. #endif
  226.     }
  227.  
  228. #ifdef FEAT_FOLDING
  229.     /* Need to update automatic folding. */
  230.     foldUpdateAll(curwin);
  231. #endif
  232.  
  233.     return retval;
  234. }
  235.  
  236. /*
  237.  * Return TRUE if "buf" points to a valid buffer (in the buffer list).
  238.  */
  239.     int
  240. buf_valid(buf)
  241.     buf_T    *buf;
  242. {
  243.     buf_T    *bp;
  244.  
  245.     for (bp = firstbuf; bp != NULL; bp = bp->b_next)
  246.     if (bp == buf)
  247.         return TRUE;
  248.     return FALSE;
  249. }
  250.  
  251. /*
  252.  * Close the link to a buffer.
  253.  * "action" is used when there is no longer a window for the buffer.
  254.  * It can be:
  255.  * 0            buffer becomes hidden
  256.  * DOBUF_UNLOAD        buffer is unloaded
  257.  * DOBUF_DELETE        buffer is unloaded and removed from buffer list
  258.  * DOBUF_WIPE        buffer is unloaded and really deleted
  259.  * When doing all but the first one on the current buffer, the caller should
  260.  * get a new buffer very soon!
  261.  *
  262.  * The 'bufhidden' option can force freeing and deleting.
  263.  */
  264.     void
  265. close_buffer(win, buf, action)
  266.     win_T    *win;        /* if not NULL, set b_last_cursor */
  267.     buf_T    *buf;
  268.     int        action;
  269. {
  270. #ifdef FEAT_AUTOCMD
  271.     int        is_curbuf;
  272.     int        nwindows = buf->b_nwindows;
  273. #endif
  274.     int        unload_buf = (action != 0);
  275.     int        del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE);
  276.     int        wipe_buf = (action == DOBUF_WIPE);
  277.  
  278. #ifdef FEAT_QUICKFIX
  279.     /*
  280.      * Force unloading or deleting when 'bufhidden' says so.
  281.      * The caller must take care of NOT deleting/freeing when 'bufhidden' is
  282.      * "hide" (otherwise we could never free or delete a buffer).
  283.      */
  284.     if (buf->b_p_bh[0] == 'd')        /* 'bufhidden' == "delete" */
  285.     {
  286.     del_buf = TRUE;
  287.     unload_buf = TRUE;
  288.     }
  289.     else if (buf->b_p_bh[0] == 'u')    /* 'bufhidden' == "unload" */
  290.     unload_buf = TRUE;
  291. #endif
  292.  
  293.     /* decrease the link count from windows (unless not in any window) */
  294.     if (buf->b_nwindows > 0)
  295.     --buf->b_nwindows;
  296.  
  297.     if (win != NULL)
  298.     {
  299.     /* Set b_last_cursor when closing the last window for the buffer.
  300.      * Remember the last cursor position and window options of the buffer.
  301.      * This used to be only for the current window, but then options like
  302.      * 'foldmethod' may be lost with a ":only" command. */
  303.     if (buf->b_nwindows == 0)
  304.         set_last_cursor(win);
  305.     buflist_setfpos(buf, win,
  306.             win->w_cursor.lnum == 1 ? 0 : win->w_cursor.lnum,
  307.             win->w_cursor.col, TRUE);
  308.     }
  309.  
  310. #ifdef FEAT_AUTOCMD
  311.     /* When the buffer is no longer in a window, trigger BufWinLeave */
  312.     if (buf->b_nwindows == 0 && nwindows > 0)
  313.     {
  314.     apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
  315.                                   FALSE, buf);
  316.     if (!buf_valid(buf))        /* autocommands may delete the buffer */
  317.         return;
  318.  
  319.     /* When the buffer becomes hidden, but is not unloaded, trigger
  320.      * BufHidden */
  321.     if (!unload_buf)
  322.     {
  323.         apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
  324.                                   FALSE, buf);
  325.         if (!buf_valid(buf))    /* autocmds may delete the buffer */
  326.         return;
  327.     }
  328.     }
  329. #endif
  330.  
  331.     /* Return when a window is displaying the buffer or when it's not
  332.      * unloaded. */
  333.     if (buf->b_nwindows > 0 || !unload_buf)
  334.     {
  335.     if (buf == curbuf)
  336.         u_sync();        /* sync undo before going to another buffer */
  337.     return;
  338.     }
  339.  
  340.     /* Always remove the buffer when there is no file name. */
  341.     if (buf->b_ffname == NULL)
  342.     del_buf = TRUE;
  343.  
  344.     /*
  345.      * Free all things allocated for this buffer.
  346.      * Also calls the "BufDelete" autocommands when del_buf is TRUE.
  347.      */
  348. #ifdef FEAT_AUTOCMD
  349.     is_curbuf = (buf == curbuf);
  350. #endif
  351.     buf_freeall(buf, del_buf);
  352. #ifdef FEAT_AUTOCMD
  353.     if (wipe_buf && buf_valid(buf))
  354.     apply_autocmds(EVENT_BUFWIPEOUT, buf->b_fname, buf->b_fname,
  355.                                   FALSE, buf);
  356.     /*
  357.      * Autocommands may have deleted the buffer.
  358.      * It's possible that autocommands change curbuf to the one being deleted.
  359.      * This might cause the previous curbuf to be deleted unexpectedly.  But
  360.      * in some cases it's OK to delete the curbuf, because a new one is
  361.      * obtained anyway.  Therefore only return if curbuf changed to the
  362.      * deleted buffer.
  363.      */
  364.     if (!buf_valid(buf) || (buf == curbuf && !is_curbuf))
  365.     return;
  366. #endif
  367.  
  368.     /*
  369.      * Remove the buffer from the list.
  370.      */
  371.     if (wipe_buf)
  372.     {
  373. #ifdef FEAT_SUN_WORKSHOP
  374.     if (usingSunWorkShop)
  375.         workshop_file_closed_lineno((char *)buf->b_ffname,
  376.             (int)buf->b_last_cursor.lnum);
  377. #endif
  378.     vim_free(buf->b_ffname);
  379.     vim_free(buf->b_sfname);
  380.     if (buf->b_prev == NULL)
  381.         firstbuf = buf->b_next;
  382.     else
  383.         buf->b_prev->b_next = buf->b_next;
  384.     if (buf->b_next == NULL)
  385.         lastbuf = buf->b_prev;
  386.     else
  387.         buf->b_next->b_prev = buf->b_prev;
  388.     free_buffer(buf);
  389.     }
  390.     else
  391.     {
  392.     if (del_buf)
  393.     {
  394.         /* Free all internal variables and reset option values, to make
  395.          * ":bdel" compatible with Vim 5.7. */
  396.         free_buffer_stuff(buf);
  397.  
  398.         /* Make it look like a new buffer. */
  399.         buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED;
  400.  
  401.         /* Init the options when loaded again. */
  402.         buf->b_p_initialized = FALSE;
  403.     }
  404.     buf_clear_file(buf);
  405.     if (del_buf)
  406.         buf->b_p_bl = FALSE;
  407.     }
  408. }
  409.  
  410. /*
  411.  * Make buffer not contain a file.
  412.  */
  413.     void
  414. buf_clear_file(buf)
  415.     buf_T    *buf;
  416. {
  417.     buf->b_ml.ml_line_count = 1;
  418.     unchanged(buf, TRUE);
  419. #ifndef SHORT_FNAME
  420.     buf->b_shortname = FALSE;
  421. #endif
  422.     buf->b_p_eol = TRUE;
  423. #ifdef FEAT_MBYTE
  424.     buf->b_p_bomb = FALSE;
  425. #endif
  426.     buf->b_ml.ml_mfp = NULL;
  427.     buf->b_ml.ml_flags = ML_EMPTY;        /* empty buffer */
  428. }
  429.  
  430. /*
  431.  * buf_freeall() - free all things allocated for a buffer that are related to
  432.  * the file.
  433.  */
  434. /*ARGSUSED*/
  435.     void
  436. buf_freeall(buf, del_buf)
  437.     buf_T    *buf;
  438.     int        del_buf;    /* buffer is going to be deleted */
  439. {
  440. #ifdef FEAT_AUTOCMD
  441.     int        is_curbuf = (buf == curbuf);
  442.  
  443.     apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname, FALSE, buf);
  444.     if (!buf_valid(buf))        /* autocommands may delete the buffer */
  445.     return;
  446.     if (del_buf && buf->b_p_bl)
  447.     {
  448.     apply_autocmds(EVENT_BUFDELETE, buf->b_fname, buf->b_fname, FALSE, buf);
  449.     if (!buf_valid(buf))        /* autocommands may delete the buffer */
  450.         return;
  451.     }
  452.     /*
  453.      * It's possible that autocommands change curbuf to the one being deleted.
  454.      * This might cause curbuf to be deleted unexpectedly.  But in some cases
  455.      * it's OK to delete the curbuf, because a new one is obtained anyway.
  456.      * Therefore only return if curbuf changed to the deleted buffer.
  457.      */
  458.     if (buf == curbuf && !is_curbuf)
  459.     return;
  460. #endif
  461. #ifdef FEAT_DIFF
  462.     diff_buf_delete(buf);        /* Can't use 'diff' for unloaded buffer. */
  463. #endif
  464. #ifdef FEAT_TCL
  465.     tcl_buffer_free(buf);
  466. #endif
  467.     u_blockfree(buf);            /* free the memory allocated for undo */
  468.     ml_close(buf, TRUE);        /* close and delete the memline/memfile */
  469.     buf->b_ml.ml_line_count = 0;    /* no lines in buffer */
  470.     u_clearall(buf);            /* reset all undo information */
  471. #ifdef FEAT_SYN_HL
  472.     syntax_clear(buf);            /* reset syntax info */
  473. #endif
  474. }
  475.  
  476. /*
  477.  * Free a buffer structure and the things it contains related to the buffer
  478.  * itself (not the file, that must have been done already).
  479.  */
  480.     static void
  481. free_buffer(buf)
  482.     buf_T    *buf;
  483. {
  484.     free_buffer_stuff(buf);
  485. #ifdef FEAT_PERL
  486.     perl_buf_free(buf);
  487. #endif
  488. #ifdef FEAT_PYTHON
  489.     python_buffer_free(buf);
  490. #endif
  491. #ifdef FEAT_RUBY
  492.     ruby_buffer_free(buf);
  493. #endif
  494.     vim_free(buf);
  495. }
  496.  
  497. /*
  498.  * Free stuff in the buffer for ":bdel" and when wiping out the buffer.
  499.  */
  500.     static void
  501. free_buffer_stuff(buf)
  502.     buf_T    *buf;
  503. {
  504.     clear_wininfo(buf);
  505. #ifdef FEAT_EVAL
  506.     var_clear(&buf->b_vars);        /* free all internal variables */
  507. #endif
  508. #ifdef FEAT_USR_CMDS
  509.     uc_clear(&buf->b_ucmds);        /* clear local user commands */
  510. #endif
  511.     free_buf_options(buf, TRUE);
  512. #ifdef FEAT_MBYTE
  513.     vim_free(buf->b_start_fenc);
  514.     buf->b_start_fenc = NULL;
  515. #endif
  516. }
  517.  
  518. /*
  519.  * Free the b_wininfo list for buffer "buf".
  520.  */
  521.     static void
  522. clear_wininfo(buf)
  523.     buf_T    *buf;
  524. {
  525.     wininfo_T    *wip;
  526.  
  527.     while (buf->b_wininfo != NULL)
  528.     {
  529.     wip = buf->b_wininfo;
  530.     buf->b_wininfo = wip->wi_next;
  531.     if (wip->wi_optset)
  532.     {
  533.         clear_winopt(&wip->wi_opt);
  534. #ifdef FEAT_FOLDING
  535.         deleteFoldRecurse(&wip->wi_folds);
  536. #endif
  537.     }
  538.     vim_free(wip);
  539.     }
  540. }
  541.  
  542. #if defined(FEAT_LISTCMDS) || defined(PROTO)
  543. /*
  544.  * Go to another buffer.  Handles the result of the ATTENTION dialog.
  545.  */
  546.     void
  547. goto_buffer(eap, start, dir, count)
  548.     exarg_T    *eap;
  549.     int        start;
  550.     int        dir;
  551.     int        count;
  552. {
  553. # if defined(FEAT_WINDOWS) \
  554.         && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
  555.     buf_T    *old_curbuf = curbuf;
  556.  
  557.     swap_exists_action = SEA_DIALOG;
  558. # endif
  559.     (void)do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
  560.                          start, dir, count, eap->forceit);
  561. # if defined(FEAT_WINDOWS) \
  562.         && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
  563.     if (swap_exists_action == SEA_QUIT && *eap->cmd == 's')
  564.     {
  565.     /* Quitting means closing the split window, nothing else. */
  566.     win_close(curwin, TRUE);
  567.     swap_exists_action = SEA_NONE;
  568.     }
  569.     else
  570.     handle_swap_exists(old_curbuf);
  571. # endif
  572. }
  573. #endif
  574.  
  575. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
  576. /*
  577.  * Handle the situation of swap_exists_action being set.
  578.  * It is allowed for "old_curbuf" to be NULL or invalid.
  579.  */
  580.     void
  581. handle_swap_exists(old_curbuf)
  582.     buf_T    *old_curbuf;
  583. {
  584.     if (swap_exists_action == SEA_QUIT)
  585.     {
  586.     /* User selected Quit at ATTENTION prompt.  Go back to previous
  587.      * buffer.  If that buffer is gone or the same as the current one,
  588.      * open a new, empty buffer. */
  589.     swap_exists_action = SEA_NONE;    /* don't want it again */
  590.     close_buffer(curwin, curbuf, DOBUF_UNLOAD);
  591.     if (!buf_valid(old_curbuf) || old_curbuf == curbuf)
  592.         old_curbuf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED);
  593.     enter_buffer(old_curbuf);
  594.     }
  595.     else if (swap_exists_action == SEA_RECOVER)
  596.     {
  597.     /* User selected Recover at ATTENTION prompt. */
  598.     msg_scroll = TRUE;
  599.     ml_recover();
  600.     MSG_PUTS("\n");    /* don't overwrite the last message */
  601.     cmdline_row = msg_row;
  602.     do_modelines();
  603.     }
  604.     swap_exists_action = SEA_NONE;
  605. }
  606. #endif
  607.  
  608. #if defined(FEAT_LISTCMDS) || defined(PROTO)
  609. /*
  610.  * do_bufdel() - delete or unload buffer(s)
  611.  *
  612.  * addr_count == 0: ":bdel" - delete current buffer
  613.  * addr_count == 1: ":N bdel" or ":bdel N [N ..]" - first delete
  614.  *            buffer "end_bnr", then any other arguments.
  615.  * addr_count == 2: ":N,N bdel" - delete buffers in range
  616.  *
  617.  * command can be DOBUF_UNLOAD (":bunload"), DOBUF_WIPE (":bwipeout") or
  618.  * DOBUF_DEL (":bdel")
  619.  *
  620.  * Returns error message or NULL
  621.  */
  622.     char_u *
  623. do_bufdel(command, arg, addr_count, start_bnr, end_bnr, forceit)
  624.     int        command;
  625.     char_u    *arg;        /* pointer to extra arguments */
  626.     int        addr_count;
  627.     int        start_bnr;    /* first buffer number in a range */
  628.     int        end_bnr;    /* buffer nr or last buffer nr in a range */
  629.     int        forceit;
  630. {
  631.     int        do_current = 0;    /* delete current buffer? */
  632.     int        deleted = 0;    /* number of buffers deleted */
  633.     char_u    *errormsg = NULL; /* return value */
  634.     int        bnr;        /* buffer number */
  635.     char_u    *p;
  636.  
  637.     if (addr_count == 0)
  638.     {
  639.     (void)do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit);
  640.     }
  641.     else
  642.     {
  643.     if (addr_count == 2)
  644.     {
  645.         if (*arg)        /* both range and argument is not allowed */
  646.         return (char_u *)_(e_trailing);
  647.         bnr = start_bnr;
  648.     }
  649.     else    /* addr_count == 1 */
  650.         bnr = end_bnr;
  651.  
  652.     for ( ;!got_int; ui_breakcheck())
  653.     {
  654.         /*
  655.          * delete the current buffer last, otherwise when the
  656.          * current buffer is deleted, the next buffer becomes
  657.          * the current one and will be loaded, which may then
  658.          * also be deleted, etc.
  659.          */
  660.         if (bnr == curbuf->b_fnum)
  661.         do_current = bnr;
  662.         else if (do_buffer(command, DOBUF_FIRST, FORWARD, (int)bnr,
  663.                                    forceit) == OK)
  664.         ++deleted;
  665.  
  666.         /*
  667.          * find next buffer number to delete/unload
  668.          */
  669.         if (addr_count == 2)
  670.         {
  671.         if (++bnr > end_bnr)
  672.             break;
  673.         }
  674.         else    /* addr_count == 1 */
  675.         {
  676.         arg = skipwhite(arg);
  677.         if (*arg == NUL)
  678.             break;
  679.         if (!isdigit(*arg))
  680.         {
  681.             p = skiptowhite_esc(arg);
  682.             bnr = buflist_findpat(arg, p, command == DOBUF_WIPE, FALSE);
  683.             if (bnr < 0)        /* failed */
  684.             break;
  685.             arg = p;
  686.         }
  687.         else
  688.             bnr = getdigits(&arg);
  689.         }
  690.     }
  691.     if (!got_int && do_current && do_buffer(command, DOBUF_FIRST,
  692.                       FORWARD, do_current, forceit) == OK)
  693.         ++deleted;
  694.  
  695.     if (deleted == 0)
  696.     {
  697.         if (command == DOBUF_UNLOAD)
  698.         sprintf((char *)IObuff, _("No buffers were unloaded"));
  699.         else if (command == DOBUF_DEL)
  700.         sprintf((char *)IObuff, _("No buffers were deleted"));
  701.         else
  702.         sprintf((char *)IObuff, _("No buffers were wiped out"));
  703.         errormsg = IObuff;
  704.     }
  705.     else if (deleted >= p_report)
  706.     {
  707.         if (command == DOBUF_UNLOAD)
  708.         {
  709.         if (deleted == 1)
  710.             smsg((char_u *)_("1 buffer unloaded"));
  711.         else
  712.             smsg((char_u *)_("%d buffers unloaded"), deleted);
  713.         }
  714.         else if (command == DOBUF_DEL)
  715.         {
  716.         if (deleted == 1)
  717.             smsg((char_u *)_("1 buffer deleted"));
  718.         else
  719.             smsg((char_u *)_("%d buffers deleted"), deleted);
  720.         }
  721.         else
  722.         {
  723.         if (deleted == 1)
  724.             smsg((char_u *)_("1 buffer wiped out"));
  725.         else
  726.             smsg((char_u *)_("%d buffers wiped out"), deleted);
  727.         }
  728.     }
  729.     }
  730.  
  731.     return errormsg;
  732. }
  733.  
  734. /*
  735.  * Implementation of the commands for the buffer list.
  736.  *
  737.  * action == DOBUF_GOTO        go to specified buffer
  738.  * action == DOBUF_SPLIT    split window and go to specified buffer
  739.  * action == DOBUF_UNLOAD   unload specified buffer(s)
  740.  * action == DOBUF_DEL        delete specified buffer(s) from buffer list
  741.  * action == DOBUF_WIPE        delete specified buffer(s) really
  742.  *
  743.  * start == DOBUF_CURRENT   go to "count" buffer from current buffer
  744.  * start == DOBUF_FIRST        go to "count" buffer from first buffer
  745.  * start == DOBUF_LAST        go to "count" buffer from last buffer
  746.  * start == DOBUF_MOD        go to "count" modified buffer from current buffer
  747.  *
  748.  * Return FAIL or OK.
  749.  */
  750.     int
  751. do_buffer(action, start, dir, count, forceit)
  752.     int        action;
  753.     int        start;
  754.     int        dir;        /* FORWARD or BACKWARD */
  755.     int        count;        /* buffer number or number of buffers */
  756.     int        forceit;    /* TRUE for :...! */
  757. {
  758.     buf_T    *buf;
  759.     buf_T    *bp;
  760.     int        unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
  761.                              || action == DOBUF_WIPE);
  762.  
  763.     switch (start)
  764.     {
  765.     case DOBUF_FIRST:   buf = firstbuf; break;
  766.     case DOBUF_LAST:    buf = lastbuf;  break;
  767.     default:        buf = curbuf;   break;
  768.     }
  769.     if (start == DOBUF_MOD)        /* find next modified buffer */
  770.     {
  771.     while (count-- > 0)
  772.     {
  773.         do
  774.         {
  775.         buf = buf->b_next;
  776.         if (buf == NULL)
  777.             buf = firstbuf;
  778.         }
  779.         while (buf != curbuf && !bufIsChanged(buf));
  780.     }
  781.     if (!bufIsChanged(buf))
  782.     {
  783.         EMSG(_("E84: No modified buffer found"));
  784.         return FAIL;
  785.     }
  786.     }
  787.     else if (start == DOBUF_FIRST && count) /* find specified buffer number */
  788.     {
  789.     while (buf != NULL && buf->b_fnum != count)
  790.         buf = buf->b_next;
  791.     }
  792.     else
  793.     {
  794.     bp = NULL;
  795.     while (count > 0 || (!unload && !buf->b_p_bl && bp != buf))
  796.     {
  797.         /* remember the buffer where we start, we come back there when all
  798.          * buffers are unlisted. */
  799.         if (bp == NULL)
  800.         bp = buf;
  801.         if (dir == FORWARD)
  802.         {
  803.         buf = buf->b_next;
  804.         if (buf == NULL)
  805.             buf = firstbuf;
  806.         }
  807.         else
  808.         {
  809.         buf = buf->b_prev;
  810.         if (buf == NULL)
  811.             buf = lastbuf;
  812.         }
  813.         /* don't count unlisted buffers */
  814.         if (unload || buf->b_p_bl)
  815.         {
  816.          --count;
  817.          bp = NULL;    /* use this buffer as new starting point */
  818.         }
  819.         if (bp == buf)
  820.         {
  821.         /* back where we started, didn't find anything. */
  822.         EMSG(_("E85: There is no listed buffer"));
  823.         return FAIL;
  824.         }
  825.     }
  826.     }
  827.  
  828.     if (buf == NULL)        /* could not find it */
  829.     {
  830.     if (start == DOBUF_FIRST)
  831.     {
  832.         /* don't warn when deleting */
  833.         if (!unload)
  834.         EMSGN(_("E86: Cannot go to buffer %ld"), count);
  835.     }
  836.     else if (dir == FORWARD)
  837.         EMSG(_("E87: Cannot go beyond last buffer"));
  838.     else
  839.         EMSG(_("E88: Cannot go before first buffer"));
  840.     return FAIL;
  841.     }
  842.  
  843. #ifdef FEAT_GUI
  844.     need_mouse_correct = TRUE;
  845. #endif
  846.  
  847. #ifdef FEAT_LISTCMDS
  848.     /*
  849.      * delete buffer buf from memory and/or the list
  850.      */
  851.     if (unload)
  852.     {
  853.     int    forward;
  854.     int    retval;
  855.  
  856.     /* When unloading or deleting a buffer that's already unloaded and
  857.      * unlisted: fail silently. */
  858.     if (action != DOBUF_WIPE && buf->b_ml.ml_mfp == NULL && !buf->b_p_bl)
  859.         return FAIL;
  860.  
  861.     if (!forceit && bufIsChanged(buf))
  862.     {
  863.         EMSGN(_("E89: No write since last change for buffer %ld (use ! to override)"),
  864.             buf->b_fnum);
  865.         return FAIL;
  866.     }
  867.  
  868.     /*
  869.      * If deleting the last (listed) buffer, make it empty.
  870.      * The last (listed) buffer cannot be unloaded.
  871.      */
  872.     for (bp = firstbuf; bp != NULL; bp = bp->b_next)
  873.         if (bp->b_p_bl && bp != buf)
  874.         break;
  875.     if (bp == NULL && buf == curbuf)
  876.     {
  877.         if (action == DOBUF_UNLOAD)
  878.         {
  879.         EMSG(_("E90: Cannot unload last buffer"));
  880.         return FAIL;
  881.         }
  882.  
  883.         /* Close any other windows on this buffer, then make it empty. */
  884. #ifdef FEAT_WINDOWS
  885.         {
  886.         win_T    *wp, *nextwp;
  887.  
  888.         for (wp = firstwin; wp != NULL; wp = nextwp)
  889.         {
  890.             nextwp = wp->w_next;
  891.             if (wp != curwin && wp->w_buffer == buf)
  892.             {
  893.             /* Start all over, autocommands may change the window
  894.              * layout. */
  895.             nextwp = firstwin;
  896.             win_close(wp, FALSE);
  897.             }
  898.         }
  899.         }
  900. #endif
  901.         setpcmark();
  902.         retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE,
  903.                           forceit ? ECMD_FORCEIT : 0);
  904.  
  905.         /*
  906.          * do_ecmd() may create a new buffer, then we have to delete
  907.          * the old one.  But do_ecmd() may have done that already, check
  908.          * if the buffer still exists.
  909.          */
  910.         if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0)
  911.         close_buffer(NULL, buf, action);
  912.         return retval;
  913.     }
  914.  
  915. #ifdef FEAT_WINDOWS
  916.     /*
  917.      * If the deleted buffer is the current one, close the current window
  918.      * (unless it's the only window).
  919.      */
  920.     while (buf == curbuf && firstwin != lastwin)
  921.         win_close(curwin, FALSE);
  922. #endif
  923.  
  924.     /*
  925.      * If the buffer to be deleted is not the current one, delete it here.
  926.      */
  927.     if (buf != curbuf)
  928.     {
  929. #ifdef FEAT_WINDOWS
  930.         close_windows(buf);
  931. #endif
  932.         if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0)
  933.         close_buffer(NULL, buf, action);
  934.         return OK;
  935.     }
  936.  
  937.     /*
  938.      * Deleting the current buffer: Need to find another buffer to go to.
  939.      * There must be another, otherwise it would have been handled above.
  940.      * First use au_new_curbuf, if it is valid.
  941.      * Then prefer the buffer we most recently visited.
  942.      * Else try to find one that is loaded, after the current buffer,
  943.      * then before the current buffer.
  944.      * Finally use any buffer.
  945.      */
  946.     buf = NULL;
  947. #ifdef FEAT_AUTOCMD
  948.     if (au_new_curbuf != NULL && buf_valid(au_new_curbuf))
  949.         buf = au_new_curbuf;
  950. # ifdef FEAT_JUMPLIST
  951.     else
  952. # endif
  953. #endif
  954. #ifdef FEAT_JUMPLIST
  955.         if (curwin->w_jumplistlen > 0)
  956.     {
  957.         int     jumpidx;
  958.  
  959.         jumpidx = curwin->w_jumplistidx - 1;
  960.         if (jumpidx < 0)
  961.         jumpidx = curwin->w_jumplistlen - 1;
  962.  
  963.         forward = jumpidx;
  964.         while (jumpidx != curwin->w_jumplistidx)
  965.         {
  966.         buf = buflist_findnr(curwin->w_jumplist[jumpidx].fmark.fnum);
  967.         if (buf == curbuf
  968.             || (buf != NULL
  969.                 && (buf->b_ml.ml_mfp == NULL || !buf->b_p_bl)))
  970.             buf = NULL;    /* Must be open, listed and not current */
  971.         /* found a valid buffer: stop searching */
  972.         if (buf != NULL)
  973.             break;
  974.         /* advance to older entry in jump list */
  975.         if (!jumpidx && curwin->w_jumplistidx == curwin->w_jumplistlen)
  976.             break;
  977.         if (--jumpidx < 0)
  978.             jumpidx = curwin->w_jumplistlen - 1;
  979.         if (jumpidx == forward)       /* List exhausted for sure */
  980.             break;
  981.         }
  982.     }
  983. #endif
  984.  
  985.     if (buf == NULL)    /* No previous buffer, Try 2'nd approach */
  986.     {
  987.         forward = TRUE;
  988.         buf = curbuf->b_next;
  989.         for (;;)
  990.         {
  991.         if (buf == NULL)
  992.         {
  993.             if (!forward)    /* tried both directions */
  994.             break;
  995.             buf = curbuf->b_prev;
  996.             forward = FALSE;
  997.             continue;
  998.         }
  999.         /* in non-help buffer, try to skip help buffers, and vv */
  1000.         if (buf->b_ml.ml_mfp != NULL
  1001.             && buf->b_help == curbuf->b_help
  1002.             && buf->b_p_bl)
  1003.             break;
  1004.         if (forward)
  1005.             buf = buf->b_next;
  1006.         else
  1007.             buf = buf->b_prev;
  1008.         }
  1009.     }
  1010.     if (buf == NULL)    /* No loaded buffer, find listed one */
  1011.     {
  1012.         for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  1013.         if (buf->b_p_bl && buf != curbuf)
  1014.             break;
  1015.     }
  1016.     if (buf == NULL)    /* Still no buffer, just take one */
  1017.     {
  1018.         if (curbuf->b_next != NULL)
  1019.         buf = curbuf->b_next;
  1020.         else
  1021.         buf = curbuf->b_prev;
  1022.     }
  1023.     }
  1024.  
  1025.     /*
  1026.      * make buf current buffer
  1027.      */
  1028.     if (action == DOBUF_SPLIT)        /* split window first */
  1029.     {
  1030. #ifdef FEAT_WINDOWS
  1031.     /* jump to first window containing buf if one exists ("useopen") */
  1032.     if (vim_strchr(p_swb, 'u') && buf_jump_open_win(buf))
  1033.         return OK;
  1034.     if (win_split(0, 0) == FAIL)
  1035. #endif
  1036.         return FAIL;
  1037.     }
  1038. #endif
  1039.  
  1040.     /* go to current buffer - nothing to do */
  1041.     if (buf == curbuf)
  1042.     return OK;
  1043.  
  1044.     /*
  1045.      * Check if the current buffer may be abandoned.
  1046.      */
  1047.     if (action == DOBUF_GOTO && !can_abandon(curbuf, forceit))
  1048.     {
  1049.     EMSG(_(e_nowrtmsg));
  1050.     return FAIL;
  1051.     }
  1052.  
  1053.     /* Go to the other buffer. */
  1054.     set_curbuf(buf, action);
  1055.  
  1056.     return OK;
  1057. }
  1058.  
  1059. #endif /* FEAT_LISTCMDS */
  1060.  
  1061. /*
  1062.  * Set current buffer to "buf".  Executes autocommands and closes current
  1063.  * buffer.  "action" tells how to close the current buffer:
  1064.  * DOBUF_GOTO        free or hide it
  1065.  * DOBUF_SPLIT        nothing
  1066.  * DOBUF_UNLOAD        unload it
  1067.  * DOBUF_DEL        delete it
  1068.  * DOBUF_WIPE        wipe it out
  1069.  */
  1070.     void
  1071. set_curbuf(buf, action)
  1072.     buf_T    *buf;
  1073.     int        action;
  1074. {
  1075.     buf_T    *prevbuf;
  1076.     int        unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
  1077.                              || action == DOBUF_WIPE);
  1078.  
  1079.     setpcmark();
  1080.     curwin->w_alt_fnum = curbuf->b_fnum; /* remember alternate file */
  1081.     buflist_altfpos();             /* remember curpos */
  1082.  
  1083.     /* close_windows() or apply_autocmds() may change curbuf */
  1084.     prevbuf = curbuf;
  1085.  
  1086. #ifdef FEAT_AUTOCMD
  1087.     apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
  1088.     if (buf_valid(prevbuf))
  1089. #endif
  1090.     {
  1091. #ifdef FEAT_WINDOWS
  1092.     if (unload)
  1093.         close_windows(prevbuf);
  1094. #endif
  1095.     if (buf_valid(prevbuf))
  1096.         close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf,
  1097.             unload ? action : (action == DOBUF_GOTO
  1098.             && !P_HID(prevbuf)
  1099.             && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0);
  1100.     }
  1101. #ifdef FEAT_AUTOCMD
  1102.     if (buf_valid(buf))        /* an autocommand may have deleted buf! */
  1103. #endif
  1104.     enter_buffer(buf);
  1105. }
  1106.  
  1107. /*
  1108.  * Enter a new current buffer.
  1109.  * Old curbuf must have been abandoned already!
  1110.  */
  1111.     void
  1112. enter_buffer(buf)
  1113.     buf_T    *buf;
  1114. {
  1115.     /* Copy buffer and window local option values.  Not for a help buffer. */
  1116.     buf_copy_options(buf, BCO_ENTER | BCO_NOHELP);
  1117.     if (!buf->b_help)
  1118.     get_winopts(buf);
  1119. #ifdef FEAT_FOLDING
  1120.     else
  1121.     /* Remove all folds in the window. */
  1122.     clearFolding(curwin);
  1123.     foldUpdateAll(curwin);    /* update folds (later). */
  1124. #endif
  1125.  
  1126.     /* Get the buffer in the current window. */
  1127.     curwin->w_buffer = buf;
  1128.     curbuf = buf;
  1129.     ++curbuf->b_nwindows;
  1130.  
  1131. #ifdef FEAT_DIFF
  1132.     diff_new_buffer();
  1133. #endif
  1134.  
  1135.     /* Make sure the buffer is loaded. */
  1136.     if (curbuf->b_ml.ml_mfp == NULL)    /* need to load the file */
  1137.     open_buffer(FALSE, NULL);
  1138.     else
  1139.     {
  1140.     need_fileinfo = TRUE;        /* display file info after redraw */
  1141.     (void)buf_check_timestamp(curbuf, FALSE); /* check if file changed */
  1142. #ifdef FEAT_AUTOCMD
  1143.     curwin->w_topline = 1;
  1144. # ifdef FEAT_DIFF
  1145.     curwin->w_topfill = 0;
  1146. # endif
  1147.     apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
  1148.     apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf);
  1149. #endif
  1150.     }
  1151.     buflist_getfpos();            /* restore curpos.lnum and possibly
  1152.                      * curpos.col */
  1153.     check_arg_idx(curwin);        /* check for valid arg_idx */
  1154. #ifdef FEAT_TITLE
  1155.     maketitle();
  1156. #endif
  1157. #ifdef FEAT_AUTOCMD
  1158.     if (curwin->w_topline == 1)        /* when autocmds didn't change it */
  1159. #endif
  1160.     scroll_cursor_halfway(FALSE);    /* redisplay at correct position */
  1161. #ifdef FEAT_SUN_WORKSHOP
  1162.     if (usingSunWorkShop && vim_chdirfile(buf->b_ffname) == OK)
  1163.     shorten_fnames(TRUE);
  1164. #endif
  1165. #ifdef FEAT_KEYMAP
  1166.     if (curbuf->b_kmap_state & KEYMAP_INIT)
  1167.     keymap_init();
  1168. #endif
  1169.     redraw_later(NOT_VALID);
  1170. }
  1171.  
  1172. /*
  1173.  * functions for dealing with the buffer list
  1174.  */
  1175.  
  1176. /*
  1177.  * Add a file name to the buffer list.  Return a pointer to the buffer.
  1178.  * If the same file name already exists return a pointer to that buffer.
  1179.  * If it does not exist, or if fname == NULL, a new entry is created.
  1180.  * If (flags & BLN_CURBUF) is TRUE, may use current buffer.
  1181.  * If (flags & BLN_LISTED) is TRUE, add new buffer to buffer list.
  1182.  * If (flags & BLN_DUMMY) is TRUE, don't count it as a real buffer.
  1183.  * This is the ONLY way to create a new buffer.
  1184.  */
  1185. static int  top_file_num = 1;        /* highest file number */
  1186.  
  1187.     buf_T *
  1188. buflist_new(ffname, sfname, lnum, flags)
  1189.     char_u    *ffname;    /* full path of fname or relative */
  1190.     char_u    *sfname;    /* short fname or NULL */
  1191.     linenr_T    lnum;        /* preferred cursor line */
  1192.     int        flags;        /* BLN_ defines */
  1193. {
  1194.     buf_T    *buf;
  1195. #ifdef UNIX
  1196.     struct stat    st;
  1197. #endif
  1198.  
  1199.     fname_expand(&ffname, &sfname);    /* will allocate ffname */
  1200.  
  1201.     /*
  1202.      * If file name already exists in the list, update the entry.
  1203.      */
  1204. #ifdef UNIX
  1205.     /* On Unix we can use inode numbers when the file exists.  Works better
  1206.      * for hard links. */
  1207.     if (sfname == NULL || mch_stat((char *)sfname, &st) < 0)
  1208.     st.st_dev = (dev_T)-1;
  1209. #endif
  1210.     if (ffname != NULL && !(flags & BLN_DUMMY) && (buf =
  1211. #ifdef UNIX
  1212.         buflist_findname_stat(ffname, &st)
  1213. #else
  1214.         buflist_findname(ffname)
  1215. #endif
  1216.         ) != NULL)
  1217.     {
  1218.     vim_free(ffname);
  1219.     if (lnum != 0)
  1220.         buflist_setfpos(buf, curwin, lnum, (colnr_T)0, FALSE);
  1221.     /* copy the options now, if 'cpo' doesn't have 's' and not done
  1222.      * already */
  1223.     buf_copy_options(buf, 0);
  1224.     return buf;
  1225.     }
  1226.  
  1227.     /*
  1228.      * If the current buffer has no name and no contents, use the current
  1229.      * buffer.    Otherwise: Need to allocate a new buffer structure.
  1230.      *
  1231.      * This is the ONLY place where a new buffer structure is allocated!
  1232.      */
  1233.     if ((flags & BLN_CURBUF)
  1234.         && curbuf != NULL
  1235.         && curbuf->b_ffname == NULL
  1236.         && curbuf->b_nwindows <= 1
  1237.         && (curbuf->b_ml.ml_mfp == NULL || bufempty()))
  1238.     {
  1239.     buf = curbuf;
  1240. #ifdef FEAT_AUTOCMD
  1241.     /* It's like this buffer is deleted. */
  1242.     if (curbuf->b_p_bl)
  1243.         apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
  1244.     apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
  1245. #endif
  1246. #ifdef FEAT_QUICKFIX
  1247.     /* Make sure 'bufhidden' and 'buftype' are empty */
  1248.     clear_string_option(&buf->b_p_bh);
  1249.     clear_string_option(&buf->b_p_bt);
  1250. #endif
  1251.     }
  1252.     else
  1253.     {
  1254.     buf = (buf_T *)alloc_clear((unsigned)sizeof(buf_T));
  1255.     if (buf == NULL)
  1256.     {
  1257.         vim_free(ffname);
  1258.         return NULL;
  1259.     }
  1260.     }
  1261.  
  1262.     if (ffname != NULL)
  1263.     {
  1264.     buf->b_ffname = ffname;
  1265.     buf->b_sfname = vim_strsave(sfname);
  1266.     }
  1267.  
  1268.     clear_wininfo(buf);
  1269.     buf->b_wininfo = (wininfo_T *)alloc_clear((unsigned)sizeof(wininfo_T));
  1270.  
  1271.     if ((ffname != NULL && (buf->b_ffname == NULL || buf->b_sfname == NULL))
  1272.         || buf->b_wininfo == NULL)
  1273.     {
  1274.     vim_free(buf->b_ffname);
  1275.     buf->b_ffname = NULL;
  1276.     vim_free(buf->b_sfname);
  1277.     buf->b_sfname = NULL;
  1278.     if (buf != curbuf)
  1279.         free_buffer(buf);
  1280.     return NULL;
  1281.     }
  1282.  
  1283.     if (buf == curbuf)
  1284.     {
  1285.     buf_freeall(buf, FALSE); /* free all things allocated for this buffer */
  1286.     if (buf != curbuf)     /* autocommands deleted the buffer! */
  1287.         return NULL;
  1288.     /* buf->b_nwindows = 0; why was this here? */
  1289. #ifdef FEAT_EVAL
  1290.     var_clear(&buf->b_vars);    /* delete internal variables */
  1291. #endif
  1292.     }
  1293.     else
  1294.     {
  1295.     /*
  1296.      * put new buffer at the end of the buffer list
  1297.      */
  1298.     buf->b_next = NULL;
  1299.     if (firstbuf == NULL)        /* buffer list is empty */
  1300.     {
  1301.         buf->b_prev = NULL;
  1302.         firstbuf = buf;
  1303.     }
  1304.     else                /* append new buffer at end of list */
  1305.     {
  1306.         lastbuf->b_next = buf;
  1307.         buf->b_prev = lastbuf;
  1308.     }
  1309.     lastbuf = buf;
  1310.  
  1311.     buf->b_fnum = top_file_num++;
  1312.     if (top_file_num < 0)        /* wrap around (may cause duplicates) */
  1313.     {
  1314.         EMSG(_("W14: Warning: List of file names overflow"));
  1315.         if (emsg_silent == 0)
  1316.         {
  1317.         out_flush();
  1318.         ui_delay(3000L, TRUE);    /* make sure it is noticed */
  1319.         }
  1320.         top_file_num = 1;
  1321.     }
  1322.  
  1323.     /*
  1324.      * Always copy the options from the current buffer.
  1325.      */
  1326.     buf_copy_options(buf, BCO_ALWAYS);
  1327.     }
  1328.  
  1329.     buf->b_wininfo->wi_fpos.lnum = lnum;
  1330.     buf->b_wininfo->wi_win = curwin;
  1331.  
  1332. #ifdef FEAT_EVAL
  1333.     var_init(&buf->b_vars);        /* init internal variables */
  1334. #endif
  1335.  
  1336.     buf->b_fname = buf->b_sfname;
  1337. #ifdef UNIX
  1338.     if (st.st_dev == (dev_T)-1)
  1339.     buf->b_dev = -1;
  1340.     else
  1341.     {
  1342.     buf->b_dev = st.st_dev;
  1343.     buf->b_ino = st.st_ino;
  1344.     }
  1345. #endif
  1346.     buf->b_u_synced = TRUE;
  1347.     buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED;
  1348.     buf_clear_file(buf);
  1349.     clrallmarks(buf);            /* clear marks */
  1350.     fmarks_check_names(buf);        /* check file marks for this file */
  1351.     buf->b_p_bl = (flags & BLN_LISTED) ? TRUE : FALSE;    /* init 'buflisted' */
  1352. #ifdef FEAT_AUTOCMD
  1353.     if (!(flags & BLN_DUMMY))
  1354.     {
  1355.     apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, buf);
  1356.     if (flags & BLN_LISTED)
  1357.         apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf);
  1358.     }
  1359. #endif
  1360.  
  1361.     return buf;
  1362. }
  1363.  
  1364. /*
  1365.  * Free the memory for the options of a buffer.
  1366.  * If "free_p_ff" is TRUE also free 'fileformat', 'buftype' and
  1367.  * 'fileencoding'.
  1368.  */
  1369.     void
  1370. free_buf_options(buf, free_p_ff)
  1371.     buf_T    *buf;
  1372.     int        free_p_ff;
  1373. {
  1374.     if (free_p_ff)
  1375.     {
  1376. #ifdef FEAT_MBYTE
  1377.     clear_string_option(&buf->b_p_fenc);
  1378. #endif
  1379.     clear_string_option(&buf->b_p_ff);
  1380. #ifdef FEAT_QUICKFIX
  1381.     clear_string_option(&buf->b_p_bh);
  1382.     clear_string_option(&buf->b_p_bt);
  1383. #endif
  1384.     }
  1385. #ifdef FEAT_FIND_ID
  1386.     clear_string_option(&buf->b_p_def);
  1387.     clear_string_option(&buf->b_p_inc);
  1388. # ifdef FEAT_EVAL
  1389.     clear_string_option(&buf->b_p_inex);
  1390. # endif
  1391. #endif
  1392. #if defined(FEAT_CINDENT) && defined(FEAT_EVAL)
  1393.     clear_string_option(&buf->b_p_inde);
  1394.     clear_string_option(&buf->b_p_indk);
  1395. #endif
  1396. #ifdef FEAT_CRYPT
  1397.     clear_string_option(&buf->b_p_key);
  1398. #endif
  1399.     clear_string_option(&buf->b_p_mps);
  1400.     clear_string_option(&buf->b_p_fo);
  1401.     clear_string_option(&buf->b_p_isk);
  1402. #ifdef FEAT_KEYMAP
  1403.     clear_string_option(&buf->b_p_keymap);
  1404.     ga_clear(&buf->b_kmap_ga);
  1405. #endif
  1406. #ifdef FEAT_COMMENTS
  1407.     clear_string_option(&buf->b_p_com);
  1408. #endif
  1409. #ifdef FEAT_FOLDING
  1410.     clear_string_option(&buf->b_p_cms);
  1411. #endif
  1412.     clear_string_option(&buf->b_p_nf);
  1413. #ifdef FEAT_SYN_HL
  1414.     clear_string_option(&buf->b_p_syn);
  1415. #endif
  1416. #ifdef FEAT_SEARCHPATH
  1417.     clear_string_option(&buf->b_p_sua);
  1418. #endif
  1419. #ifdef FEAT_AUTOCMD
  1420.     clear_string_option(&buf->b_p_ft);
  1421. #endif
  1422. #ifdef FEAT_OSFILETYPE
  1423.     clear_string_option(&buf->b_p_oft);
  1424. #endif
  1425. #ifdef FEAT_CINDENT
  1426.     clear_string_option(&buf->b_p_cink);
  1427.     clear_string_option(&buf->b_p_cino);
  1428. #endif
  1429. #if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT)
  1430.     clear_string_option(&buf->b_p_cinw);
  1431. #endif
  1432. #ifdef FEAT_INS_EXPAND
  1433.     clear_string_option(&buf->b_p_cpt);
  1434. #endif
  1435. #ifdef FEAT_QUICKFIX
  1436.     clear_string_option(&buf->b_p_gp);
  1437.     clear_string_option(&buf->b_p_mp);
  1438.     clear_string_option(&buf->b_p_efm);
  1439. #endif
  1440.     clear_string_option(&buf->b_p_ep);
  1441.     clear_string_option(&buf->b_p_path);
  1442.     clear_string_option(&buf->b_p_tags);
  1443. #ifdef FEAT_INS_EXPAND
  1444.     clear_string_option(&buf->b_p_dict);
  1445.     clear_string_option(&buf->b_p_tsr);
  1446. #endif
  1447.     buf->b_p_ar = -1;
  1448. }
  1449.  
  1450. /*
  1451.  * get alternate file n
  1452.  * set linenr to lnum or altfpos.lnum if lnum == 0
  1453.  *    also set cursor column to altfpos.col if 'startofline' is not set.
  1454.  * if (options & GETF_SETMARK) call setpcmark()
  1455.  * if (options & GETF_ALT) we are jumping to an alternate file.
  1456.  * if (options & GETF_SWITCH) respect 'switchbuf' settings when jumping
  1457.  *
  1458.  * return FAIL for failure, OK for success
  1459.  */
  1460.     int
  1461. buflist_getfile(n, lnum, options, forceit)
  1462.     int        n;
  1463.     linenr_T    lnum;
  1464.     int        options;
  1465.     int        forceit;
  1466. {
  1467.     buf_T    *buf;
  1468. #ifdef FEAT_WINDOWS
  1469.     win_T    *wp = NULL;
  1470. #endif
  1471.     pos_T    *fpos;
  1472.     colnr_T    col;
  1473.  
  1474.     buf = buflist_findnr(n);
  1475.     if (buf == NULL)
  1476.     {
  1477.     if ((options & GETF_ALT) && n == 0)
  1478.         EMSG(_(e_noalt));
  1479.     else
  1480.         EMSGN(_("E92: Buffer %ld not found"), n);
  1481.     return FAIL;
  1482.     }
  1483.  
  1484.     /* if alternate file is the current buffer, nothing to do */
  1485.     if (buf == curbuf)
  1486.     return OK;
  1487.  
  1488. #ifdef FEAT_CMDWIN
  1489.     if (cmdwin_type != 0)
  1490.     return FAIL;
  1491. #endif
  1492.  
  1493.     /* altfpos may be changed by getfile(), get it now */
  1494.     if (lnum == 0)
  1495.     {
  1496.     fpos = buflist_findfpos(buf);
  1497.     lnum = fpos->lnum;
  1498.     col = fpos->col;
  1499.     }
  1500.     else
  1501.     col = 0;
  1502.  
  1503. #ifdef FEAT_WINDOWS
  1504.     if (options & GETF_SWITCH)
  1505.     {
  1506.     /* use existing open window for buffer if wanted */
  1507.     if (vim_strchr(p_swb, 'u'))     /* useopen */
  1508.         wp = buf_jump_open_win(buf);
  1509.     /* split window if wanted ("split") */
  1510.     if (wp == NULL && vim_strchr(p_swb, 't') && !bufempty()
  1511.         && win_split(0, 0) == FAIL)
  1512.         return FAIL;
  1513.     }
  1514. #endif
  1515.  
  1516.     ++RedrawingDisabled;
  1517.     if (getfile(buf->b_fnum, NULL, NULL, (options & GETF_SETMARK),
  1518.                               lnum, forceit) <= 0)
  1519.     {
  1520.     --RedrawingDisabled;
  1521.  
  1522.     /* cursor is at to BOL and w_cursor.lnum is checked due to getfile() */
  1523.     if (!p_sol && col != 0)
  1524.     {
  1525.         curwin->w_cursor.col = col;
  1526.         check_cursor_col();
  1527. #ifdef FEAT_VIRTUALEDIT
  1528.         curwin->w_cursor.coladd = 0;
  1529. #endif
  1530.         curwin->w_set_curswant = TRUE;
  1531.     }
  1532.     return OK;
  1533.     }
  1534.     --RedrawingDisabled;
  1535.     return FAIL;
  1536. }
  1537.  
  1538. /*
  1539.  * go to the last know line number for the current buffer
  1540.  */
  1541.     void
  1542. buflist_getfpos()
  1543. {
  1544.     pos_T    *fpos;
  1545.  
  1546.     fpos = buflist_findfpos(curbuf);
  1547.  
  1548.     curwin->w_cursor.lnum = fpos->lnum;
  1549.     check_cursor_lnum();
  1550.  
  1551.     if (p_sol)
  1552.     curwin->w_cursor.col = 0;
  1553.     else
  1554.     {
  1555.     curwin->w_cursor.col = fpos->col;
  1556.     check_cursor_col();
  1557. #ifdef FEAT_VIRTUALEDIT
  1558.     curwin->w_cursor.coladd = 0;
  1559. #endif
  1560.     curwin->w_set_curswant = TRUE;
  1561.     }
  1562. }
  1563.  
  1564. /*
  1565.  * find file in buffer list by name (it has to be for the current window)
  1566.  * 'ffname' must have a full path.
  1567.  */
  1568.     buf_T *
  1569. buflist_findname(ffname)
  1570.     char_u    *ffname;
  1571. {
  1572. #ifdef UNIX
  1573.     struct stat st;
  1574.  
  1575.     if (mch_stat((char *)ffname, &st) < 0)
  1576.     st.st_dev = (dev_T)-1;
  1577.     return buflist_findname_stat(ffname, &st);
  1578. }
  1579.  
  1580. /*
  1581.  * Same as buflist_findname(), but pass the stat structure to avoid getting it
  1582.  * twice for the same file.
  1583.  */
  1584.     static buf_T *
  1585. buflist_findname_stat(ffname, stp)
  1586.     char_u    *ffname;
  1587.     struct stat    *stp;
  1588. {
  1589. #endif
  1590.     buf_T    *buf;
  1591.  
  1592.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  1593.     if (!otherfile_buf(buf, ffname
  1594. #ifdef UNIX
  1595.             , stp
  1596. #endif
  1597.             ))
  1598.         return buf;
  1599.     return NULL;
  1600. }
  1601.  
  1602. #if defined(FEAT_LISTCMDS) || defined(FEAT_EVAL) || defined(FEAT_PERL) || defined(PROTO)
  1603. /*
  1604.  * Find file in buffer list by a regexp pattern.
  1605.  * Return fnum of the found buffer.
  1606.  * Return < 0 for error.
  1607.  */
  1608. /*ARGSUSED*/
  1609.     int
  1610. buflist_findpat(pattern, pattern_end, unlisted, diffmode)
  1611.     char_u    *pattern;
  1612.     char_u    *pattern_end;    /* pointer to first char after pattern */
  1613.     int        unlisted;    /* find unlisted buffers */
  1614.     int        diffmode;    /* find diff-mode buffers only */
  1615. {
  1616.     buf_T    *buf;
  1617.     regprog_T    *prog;
  1618.     int        match = -1;
  1619.     int        find_listed;
  1620.     char_u    *pat;
  1621.     char_u    *patend;
  1622.     int        attempt;
  1623.     char_u    *p;
  1624.     int        toggledollar;
  1625.  
  1626.     if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#'))
  1627.     {
  1628.     if (*pattern == '%')
  1629.         match = curbuf->b_fnum;
  1630.     else
  1631.         match = curwin->w_alt_fnum;
  1632. #ifdef FEAT_DIFF
  1633.     if (diffmode && !diff_mode_buf(buflist_findnr(match)))
  1634.         match = -1;
  1635. #endif
  1636.     }
  1637.  
  1638.     /*
  1639.      * Try four ways of matching:
  1640.      * attempt == 0: without '^' or '$' (at any position)
  1641.      * attempt == 1: with '^' at start (only at postion 0)
  1642.      * attempt == 2: with '$' at end (only match at end)
  1643.      * attempt == 3: with '^' at start and '$' at end (only full match)
  1644.      */
  1645.     else
  1646.     {
  1647.     pat = file_pat_to_reg_pat(pattern, pattern_end, NULL, FALSE);
  1648.     if (pat == NULL)
  1649.         return -1;
  1650.     patend = pat + STRLEN(pat) - 1;
  1651.     toggledollar = (patend > pat && *patend == '$');
  1652.  
  1653.     for (attempt = 0; attempt <= 3; ++attempt)
  1654.     {
  1655.         /* may add '^' and '$' */
  1656.         if (toggledollar)
  1657.         *patend = (attempt < 2) ? NUL : '$';    /* add/remove '$' */
  1658.         p = pat;
  1659.         if (*p == '^' && !(attempt & 1))        /* add/remove '^' */
  1660.         ++p;
  1661.         prog = vim_regcomp(p, (int)p_magic);
  1662.         if (prog == NULL)
  1663.         {
  1664.         vim_free(pat);
  1665.         return -1;
  1666.         }
  1667.  
  1668.         /* First try finding a listed buffer, if not found and "unlisted"
  1669.          * is TRUE, try finding an unlisted buffer. */
  1670.         find_listed = TRUE;
  1671.         for (;;)
  1672.         {
  1673.         for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  1674.             if (buf->b_p_bl == find_listed
  1675. #ifdef FEAT_DIFF
  1676.                 && (!diffmode || diff_mode_buf(buf))
  1677. #endif
  1678.                 && buflist_match(prog, buf) != NULL)
  1679.             {
  1680.             if (match >= 0)        /* already found a match */
  1681.             {
  1682.                 match = -2;
  1683.                 break;
  1684.             }
  1685.             match = buf->b_fnum;    /* remember first match */
  1686.             }
  1687.         if (!unlisted || !find_listed || match >= 0)
  1688.             break;
  1689.         find_listed = FALSE;
  1690.         }
  1691.  
  1692.         vim_free(prog);
  1693.         if (match >= 0)            /* found one match */
  1694.         break;
  1695.     }
  1696.     vim_free(pat);
  1697.     }
  1698.  
  1699.     if (match == -2)
  1700.     EMSG2(_("E93: More than one match for %s"), pattern);
  1701.     else if (match < 0)
  1702.     EMSG2(_("E94: No matching buffer for %s"), pattern);
  1703.     return match;
  1704. }
  1705. #endif
  1706.  
  1707. #if defined(FEAT_CMDL_COMPL) || defined(PROTO)
  1708.  
  1709. /*
  1710.  * Find all buffer names that match.
  1711.  * For command line expansion of ":buf" and ":sbuf".
  1712.  * Return OK if matches found, FAIL otherwise.
  1713.  */
  1714.     int
  1715. ExpandBufnames(pat, num_file, file, options)
  1716.     char_u    *pat;
  1717.     int        *num_file;
  1718.     char_u    ***file;
  1719.     int        options;
  1720. {
  1721.     int        count = 0;
  1722.     buf_T    *buf;
  1723.     int        round;
  1724.     char_u    *p;
  1725.     int        attempt;
  1726.     regprog_T    *prog;
  1727.  
  1728.     *num_file = 0;            /* return values in case of FAIL */
  1729.     *file = NULL;
  1730.  
  1731.     /*
  1732.      * attempt == 1: try match with    '^', match at start
  1733.      * attempt == 2: try match without '^', match anywhere
  1734.      */
  1735.     for (attempt = 1; attempt <= 2; ++attempt)
  1736.     {
  1737.     if (attempt == 2)
  1738.     {
  1739.         if (*pat != '^')        /* there's no '^', no need to try again */
  1740.         break;
  1741.         ++pat;            /* skip the '^' */
  1742.     }
  1743.     prog = vim_regcomp(pat, (int)p_magic);
  1744.     if (prog == NULL)
  1745.         return FAIL;
  1746.  
  1747.     /*
  1748.      * round == 1: Count the matches.
  1749.      * round == 2: Build the array to keep the matches.
  1750.      */
  1751.     for (round = 1; round <= 2; ++round)
  1752.     {
  1753.         count = 0;
  1754.         for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  1755.         {
  1756.         if (!buf->b_p_bl)    /* skip unlisted buffers */
  1757.             continue;
  1758.         p = buflist_match(prog, buf);
  1759.         if (p != NULL)
  1760.         {
  1761.             if (round == 1)
  1762.             ++count;
  1763.             else
  1764.             {
  1765.             if (options & WILD_HOME_REPLACE)
  1766.                 p = home_replace_save(buf, p);
  1767.             else
  1768.                 p = vim_strsave(p);
  1769.             (*file)[count++] = p;
  1770.             }
  1771.         }
  1772.         }
  1773.         if (count == 0)    /* no match found, break here */
  1774.         break;
  1775.         if (round == 1)
  1776.         {
  1777.         *file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
  1778.         if (*file == NULL)
  1779.         {
  1780.             vim_free(prog);
  1781.             return FAIL;
  1782.         }
  1783.         }
  1784.     }
  1785.     vim_free(prog);
  1786.     if (count)        /* match(es) found, break here */
  1787.         break;
  1788.     }
  1789.  
  1790.     *num_file = count;
  1791.     return (count == 0 ? FAIL : OK);
  1792. }
  1793.  
  1794. #endif /* FEAT_CMDL_COMPL */
  1795.  
  1796. #ifdef HAVE_BUFLIST_MATCH
  1797. /*
  1798.  * Check for a match on the file name for buffer "buf" with regprog "prog".
  1799.  */
  1800.     static char_u *
  1801. buflist_match(prog, buf)
  1802.     regprog_T    *prog;
  1803.     buf_T    *buf;
  1804. {
  1805.     char_u    *match;
  1806.  
  1807.     /* First try the short file name, then the long file name. */
  1808.     match = fname_match(prog, buf->b_sfname);
  1809.     if (match == NULL)
  1810.     match = fname_match(prog, buf->b_ffname);
  1811.  
  1812.     return match;
  1813. }
  1814.  
  1815. /*
  1816.  * Try matching the regexp in "prog" with file name "name".
  1817.  * Return "name" when there is a match, NULL when not.
  1818.  */
  1819.     static char_u *
  1820. fname_match(prog, name)
  1821.     regprog_T    *prog;
  1822.     char_u    *name;
  1823. {
  1824.     char_u    *match = NULL;
  1825.     char_u    *p;
  1826.     regmatch_T    regmatch;
  1827.  
  1828.     if (name != NULL)
  1829.     {
  1830.     regmatch.regprog = prog;
  1831. #ifdef CASE_INSENSITIVE_FILENAME
  1832.     regmatch.rm_ic = TRUE;        /* Always ignore case */
  1833. #else
  1834.     regmatch.rm_ic = FALSE;        /* Never ignore case */
  1835. #endif
  1836.  
  1837.     if (vim_regexec(®match, name, (colnr_T)0))
  1838.         match = name;
  1839.     else
  1840.     {
  1841.         /* Replace $(HOME) with '~' and try matching again. */
  1842.         p = home_replace_save(NULL, name);
  1843.         if (p != NULL && vim_regexec(®match, p, (colnr_T)0))
  1844.         match = name;
  1845.         vim_free(p);
  1846.     }
  1847.     }
  1848.  
  1849.     return match;
  1850. }
  1851. #endif
  1852.  
  1853. /*
  1854.  * find file in buffer list by number
  1855.  */
  1856.     buf_T *
  1857. buflist_findnr(nr)
  1858.     int        nr;
  1859. {
  1860.     buf_T    *buf;
  1861.  
  1862.     if (nr == 0)
  1863.     nr = curwin->w_alt_fnum;
  1864.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  1865.     if (buf->b_fnum == nr)
  1866.         return (buf);
  1867.     return NULL;
  1868. }
  1869.  
  1870. /*
  1871.  * Get name of file 'n' in the buffer list.
  1872.  * home_replace() is used to shorten the file name (used for marks).
  1873.  * Returns a pointer to allocated memory, of NULL when failed.
  1874.  */
  1875.     char_u *
  1876. buflist_nr2name(n, fullname, helptail)
  1877.     int        n;
  1878.     int        fullname;
  1879.     int        helptail;    /* for help buffers return tail only */
  1880. {
  1881.     buf_T    *buf;
  1882.  
  1883.     buf = buflist_findnr(n);
  1884.     if (buf == NULL)
  1885.     return NULL;
  1886.     return home_replace_save(helptail ? buf : NULL,
  1887.                      fullname ? buf->b_ffname : buf->b_fname);
  1888. }
  1889.  
  1890. /*
  1891.  * Set the "lnum" and "col" for the buffer "buf" and the current window.
  1892.  * When "copy_options" is TRUE save the local window option values.
  1893.  * When "lnum" is 0 only do the options.
  1894.  */
  1895.     static void
  1896. buflist_setfpos(buf, win, lnum, col, copy_options)
  1897.     buf_T    *buf;
  1898.     win_T    *win;
  1899.     linenr_T    lnum;
  1900.     colnr_T    col;
  1901.     int        copy_options;
  1902. {
  1903.     wininfo_T    *wip;
  1904.  
  1905.     for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
  1906.     if (wip->wi_win == win)
  1907.         break;
  1908.     if (wip == NULL)
  1909.     {
  1910.     /* allocate a new entry */
  1911.     wip = (wininfo_T *)alloc_clear((unsigned)sizeof(wininfo_T));
  1912.     if (wip == NULL)
  1913.         return;
  1914.     wip->wi_win = win;
  1915.     if (lnum == 0)        /* set lnum even when it's 0 */
  1916.         lnum = 1;
  1917.     }
  1918.     else
  1919.     {
  1920.     /* remove the entry from the list */
  1921.     if (wip->wi_prev)
  1922.         wip->wi_prev->wi_next = wip->wi_next;
  1923.     else
  1924.         buf->b_wininfo = wip->wi_next;
  1925.     if (wip->wi_next)
  1926.         wip->wi_next->wi_prev = wip->wi_prev;
  1927.     if (copy_options && wip->wi_optset)
  1928.     {
  1929.         clear_winopt(&wip->wi_opt);
  1930. #ifdef FEAT_FOLDING
  1931.         deleteFoldRecurse(&wip->wi_folds);
  1932. #endif
  1933.     }
  1934.     }
  1935.     if (lnum != 0)
  1936.     {
  1937.     wip->wi_fpos.lnum = lnum;
  1938.     wip->wi_fpos.col = col;
  1939.     }
  1940.     if (copy_options)
  1941.     {
  1942.     /* Save the window-specific option values. */
  1943.     copy_winopt(&win->w_onebuf_opt, &wip->wi_opt);
  1944. #ifdef FEAT_FOLDING
  1945.     wip->wi_fold_manual = win->w_fold_manual;
  1946.     cloneFoldGrowArray(&win->w_folds, &wip->wi_folds);
  1947. #endif
  1948.     wip->wi_optset = TRUE;
  1949.     }
  1950.  
  1951.     /* insert the entry in front of the list */
  1952.     wip->wi_next = buf->b_wininfo;
  1953.     buf->b_wininfo = wip;
  1954.     wip->wi_prev = NULL;
  1955.     if (wip->wi_next)
  1956.     wip->wi_next->wi_prev = wip;
  1957.  
  1958.     return;
  1959. }
  1960.  
  1961. /*
  1962.  * Find info for the current window in buffer "buf".
  1963.  * If not found, return the info for the most recently used window.
  1964.  * Returns NULL when there isn't any info.
  1965.  */
  1966.     static wininfo_T *
  1967. find_wininfo(buf)
  1968.     buf_T    *buf;
  1969. {
  1970.     wininfo_T    *wip;
  1971.  
  1972.     for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
  1973.     if (wip->wi_win == curwin)
  1974.         break;
  1975.     if (wip == NULL)    /* if no fpos for curwin, use the first in the list */
  1976.     wip = buf->b_wininfo;
  1977.     return wip;
  1978. }
  1979.  
  1980. /*
  1981.  * Reset the local window options to the values last used in this window.
  1982.  * If the buffer wasn't used in this window before, use the values from
  1983.  * the most recently used window.  If the values were never set, use the
  1984.  * global values for the window.
  1985.  */
  1986.     void
  1987. get_winopts(buf)
  1988.     buf_T    *buf;
  1989. {
  1990.     wininfo_T    *wip;
  1991.  
  1992.     clear_winopt(&curwin->w_onebuf_opt);
  1993. #ifdef FEAT_FOLDING
  1994.     clearFolding(curwin);
  1995. #endif
  1996.  
  1997.     wip = find_wininfo(buf);
  1998.     if (wip != NULL && wip->wi_optset)
  1999.     {
  2000.     copy_winopt(&wip->wi_opt, &curwin->w_onebuf_opt);
  2001. #ifdef FEAT_FOLDING
  2002.     curwin->w_fold_manual = wip->wi_fold_manual;
  2003.     curwin->w_foldinvalid = TRUE;
  2004.     cloneFoldGrowArray(&wip->wi_folds, &curwin->w_folds);
  2005. #endif
  2006.     }
  2007.     else
  2008.     copy_winopt(&curwin->w_allbuf_opt, &curwin->w_onebuf_opt);
  2009.  
  2010. #ifdef FEAT_FOLDING
  2011.     /* Set 'foldlevel' to 'foldlevelstart' if it's not negative. */
  2012.     if (p_fdls >= 0)
  2013.     curwin->w_p_fdl = p_fdls;
  2014. #endif
  2015. }
  2016.  
  2017. /*
  2018.  * Find the position (lnum and col) for the buffer 'buf' for the current
  2019.  * window.
  2020.  * Returns a pointer to no_position if no position is found.
  2021.  */
  2022.     pos_T *
  2023. buflist_findfpos(buf)
  2024.     buf_T    *buf;
  2025. {
  2026.     wininfo_T    *wip;
  2027.     static pos_T no_position = {1, 0};
  2028.  
  2029.     wip = find_wininfo(buf);
  2030.     if (wip != NULL)
  2031.     return &(wip->wi_fpos);
  2032.     else
  2033.     return &no_position;
  2034. }
  2035.  
  2036. /*
  2037.  * Find the lnum for the buffer 'buf' for the current window.
  2038.  */
  2039.     linenr_T
  2040. buflist_findlnum(buf)
  2041.     buf_T    *buf;
  2042. {
  2043.     return buflist_findfpos(buf)->lnum;
  2044. }
  2045.  
  2046. #if defined(FEAT_LISTCMDS) || defined(PROTO)
  2047. /*
  2048.  * List all know file names (for :files and :buffers command).
  2049.  */
  2050. /*ARGSUSED*/
  2051.     void
  2052. buflist_list(eap)
  2053.     exarg_T    *eap;
  2054. {
  2055.     buf_T    *buf;
  2056.     int        len;
  2057.     int        i;
  2058.     char    *mod;
  2059.  
  2060.     for (buf = firstbuf; buf != NULL && !got_int; buf = buf->b_next)
  2061.     {
  2062.     /* skip unlisted buffers, unless ! was used */
  2063.     if (!buf->b_p_bl && !eap->forceit)
  2064.         continue;
  2065.     msg_putchar('\n');
  2066.     if (buf_spname(buf) != NULL)
  2067.         STRCPY(NameBuff, buf_spname(buf));
  2068.     else
  2069.         home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
  2070.  
  2071.     switch (bufIsChanged(buf) + (buf->b_p_ro * 2) + (!buf->b_p_ma * 4))
  2072.     {
  2073.         default: mod = "  "; break;
  2074.         case 1: mod = " +"; break;
  2075.         case 2: mod = "= "; break;
  2076.         case 3: mod = "=+"; break;
  2077.         case 4:
  2078.         case 6: mod = "- "; break;
  2079.         case 5:
  2080.         case 7: mod = "-+"; break;
  2081.     }
  2082.  
  2083.     sprintf((char *)IObuff, "%3d%c%c%c%s \"",
  2084.         buf->b_fnum,
  2085.         buf->b_p_bl ? ' ' : 'u',
  2086.         buf == curbuf ? '%' :
  2087.             (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '),
  2088.         buf->b_ml.ml_mfp == NULL ? ' ' :
  2089.             (buf->b_nwindows == 0 ? 'h' : 'a'),
  2090.         mod);
  2091.  
  2092.     len = (int)STRLEN(IObuff);
  2093.     STRNCPY(IObuff + len, NameBuff, IOSIZE - 20 - len);
  2094.  
  2095.     len = (int)STRLEN(IObuff);
  2096.     IObuff[len++] = '"';
  2097.  
  2098.     /* put "line 999" in column 40 or after the file name */
  2099.     IObuff[len] = NUL;
  2100.     i = 40 - vim_strsize(IObuff);
  2101.     do
  2102.     {
  2103.         IObuff[len++] = ' ';
  2104.     } while (--i > 0 && len < IOSIZE - 18);
  2105.     sprintf((char *)IObuff + len, _("line %ld"),
  2106.         buf == curbuf ? curwin->w_cursor.lnum :
  2107.                 (long)buflist_findlnum(buf));
  2108.     msg_outtrans(IObuff);
  2109.     out_flush();        /* output one line at a time */
  2110.     ui_breakcheck();
  2111.     }
  2112. }
  2113. #endif
  2114.  
  2115. /*
  2116.  * Get file name and line number for file 'fnum'.
  2117.  * Used by DoOneCmd() for translating '%' and '#'.
  2118.  * Used by insert_reg() and cmdline_paste() for '#' register.
  2119.  * Return FAIL if not found, OK for success.
  2120.  */
  2121.     int
  2122. buflist_name_nr(fnum, fname, lnum)
  2123.     int        fnum;
  2124.     char_u    **fname;
  2125.     linenr_T    *lnum;
  2126. {
  2127.     buf_T    *buf;
  2128.  
  2129.     buf = buflist_findnr(fnum);
  2130.     if (buf == NULL || buf->b_fname == NULL)
  2131.     return FAIL;
  2132.  
  2133.     *fname = buf->b_fname;
  2134.     *lnum = buflist_findlnum(buf);
  2135.  
  2136.     return OK;
  2137. }
  2138.  
  2139. /*
  2140.  * Set the current file name to 'ffname', short file name to 'sfname'.
  2141.  * The file name with the full path is also remembered, for when :cd is used.
  2142.  * Returns FAIL for failure (file name already in use by other buffer)
  2143.  *    OK otherwise.
  2144.  */
  2145.     int
  2146. setfname(ffname, sfname, message)
  2147.     char_u *ffname, *sfname;
  2148.     int        message;
  2149. {
  2150.     buf_T    *buf;
  2151. #ifdef UNIX
  2152.     struct stat st;
  2153. #endif
  2154.  
  2155.     if (ffname == NULL || *ffname == NUL)
  2156.     {
  2157.     vim_free(curbuf->b_ffname);
  2158.     vim_free(curbuf->b_sfname);
  2159.     curbuf->b_ffname = NULL;
  2160.     curbuf->b_sfname = NULL;
  2161. #ifdef UNIX
  2162.     st.st_dev = (dev_T)-1;
  2163. #endif
  2164.     }
  2165.     else
  2166.     {
  2167.     fname_expand(&ffname, &sfname);        /* will allocate ffname */
  2168.     if (ffname == NULL)            /* out of memory */
  2169.         return FAIL;
  2170.  
  2171.     /*
  2172.      * if the file name is already used in another buffer:
  2173.      * - if the buffer is loaded, fail
  2174.      * - if the buffer is not loaded, delete it from the list
  2175.      */
  2176. #ifdef UNIX
  2177.     if (mch_stat((char *)ffname, &st) < 0)
  2178.         st.st_dev = (dev_T)-1;
  2179.     buf = buflist_findname_stat(ffname, &st);
  2180. #else
  2181.     buf = buflist_findname(ffname);
  2182. #endif
  2183.     if (buf != NULL && buf != curbuf)
  2184.     {
  2185.         if (buf->b_ml.ml_mfp != NULL)    /* it's loaded, fail */
  2186.         {
  2187.         if (message)
  2188.             EMSG(_("E95: Buffer with this name already exists"));
  2189.         vim_free(ffname);
  2190.         return FAIL;
  2191.         }
  2192.         close_buffer(NULL, buf, DOBUF_WIPE); /* delete from the list */
  2193.     }
  2194.     sfname = vim_strsave(sfname);
  2195.     if (ffname == NULL || sfname == NULL)
  2196.     {
  2197.         vim_free(sfname);
  2198.         vim_free(ffname);
  2199.         return FAIL;
  2200.     }
  2201. #ifdef USE_FNAME_CASE
  2202. # ifdef USE_LONG_FNAME
  2203.     if (USE_LONG_FNAME)
  2204. # endif
  2205.         fname_case(sfname, 0);    /* set correct case for short file name */
  2206. #endif
  2207.     vim_free(curbuf->b_ffname);
  2208.     vim_free(curbuf->b_sfname);
  2209.     curbuf->b_ffname = ffname;
  2210.     curbuf->b_sfname = sfname;
  2211.     }
  2212.     curbuf->b_fname = curbuf->b_sfname;
  2213. #ifdef UNIX
  2214.     if (st.st_dev == (dev_T)-1)
  2215.     curbuf->b_dev = -1;
  2216.     else
  2217.     {
  2218.     curbuf->b_dev = st.st_dev;
  2219.     curbuf->b_ino = st.st_ino;
  2220.     }
  2221. #endif
  2222.  
  2223. #ifndef SHORT_FNAME
  2224.     curbuf->b_shortname = FALSE;
  2225. #endif
  2226.  
  2227.     buf_name_changed();
  2228.     return OK;
  2229. }
  2230.  
  2231. /*
  2232.  * Take care of what needs to be done when the name of the current buffer has
  2233.  * changed.
  2234.  */
  2235.     void
  2236. buf_name_changed()
  2237. {
  2238.     /*
  2239.      * If the file name changed, also change the name of the swapfile
  2240.      */
  2241.     if (curbuf->b_ml.ml_mfp != NULL)
  2242.     ml_setname();
  2243.  
  2244.     check_arg_idx(curwin);    /* check file name for arg list */
  2245. #ifdef FEAT_TITLE
  2246.     maketitle();        /* set window title */
  2247. #endif
  2248. #ifdef FEAT_WINDOWS
  2249.     status_redraw_all();    /* status lines need to be redrawn */
  2250. #endif
  2251.     fmarks_check_names(curbuf);    /* check named file marks */
  2252.     ml_timestamp(curbuf);    /* reset timestamp */
  2253. }
  2254.  
  2255. /*
  2256.  * set alternate file name for current window
  2257.  *
  2258.  * Used by do_one_cmd(), do_write() and do_ecmd().
  2259.  * Return the buffer.
  2260.  */
  2261.     buf_T *
  2262. setaltfname(ffname, sfname, lnum)
  2263.     char_u    *ffname;
  2264.     char_u    *sfname;
  2265.     linenr_T    lnum;
  2266. {
  2267.     buf_T    *buf;
  2268.  
  2269.     /* Create a buffer.  'buflisted' is not set if it's a new buffer */
  2270.     buf = buflist_new(ffname, sfname, lnum, 0);
  2271.     if (buf != NULL)
  2272.     curwin->w_alt_fnum = buf->b_fnum;
  2273.     return buf;
  2274. }
  2275.  
  2276. /*
  2277.  * Get alternate file name for current window.
  2278.  * Return NULL if there isn't any, and give error message if requested.
  2279.  */
  2280.     char_u  *
  2281. getaltfname(errmsg)
  2282.     int        errmsg;        /* give error message */
  2283. {
  2284.     char_u    *fname;
  2285.     linenr_T    dummy;
  2286.  
  2287.     if (buflist_name_nr(0, &fname, &dummy) == FAIL)
  2288.     {
  2289.     if (errmsg)
  2290.         EMSG(_(e_noalt));
  2291.     return NULL;
  2292.     }
  2293.     return fname;
  2294. }
  2295.  
  2296. /*
  2297.  * Add a file name to the buflist and return its number.
  2298.  * Uses same flags as buflist_new(), except BLN_DUMMY.
  2299.  *
  2300.  * used by qf_init(), main() and doarglist()
  2301.  */
  2302.     int
  2303. buflist_add(fname, flags)
  2304.     char_u    *fname;
  2305.     int        flags;
  2306. {
  2307.     buf_T    *buf;
  2308.  
  2309.     buf = buflist_new(fname, NULL, (linenr_T)0, flags);
  2310.     if (buf != NULL)
  2311.     return buf->b_fnum;
  2312.     return 0;
  2313. }
  2314.  
  2315. #if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
  2316. /*
  2317.  * Adjust slashes in file names.  Called after 'shellslash' was set.
  2318.  */
  2319.     void
  2320. buflist_slash_adjust()
  2321. {
  2322.     buf_T    *bp;
  2323.  
  2324.     for (bp = firstbuf; bp != NULL; bp = bp->b_next)
  2325.     {
  2326.     if (bp->b_ffname != NULL)
  2327.         slash_adjust(bp->b_ffname);
  2328.     if (bp->b_sfname != NULL)
  2329.         slash_adjust(bp->b_sfname);
  2330.     }
  2331. }
  2332. #endif
  2333.  
  2334. /*
  2335.  * Set alternate cursor position for current window.
  2336.  * Also save the local window option values.
  2337.  */
  2338.     void
  2339. buflist_altfpos()
  2340. {
  2341.     buflist_setfpos(curbuf, curwin, curwin->w_cursor.lnum,
  2342.                           curwin->w_cursor.col, TRUE);
  2343. }
  2344.  
  2345. /*
  2346.  * Return TRUE if 'ffname' is not the same file as current file.
  2347.  * Fname must have a full path (expanded by mch_FullName()).
  2348.  */
  2349.     int
  2350. otherfile(ffname)
  2351.     char_u    *ffname;
  2352. {
  2353.     return otherfile_buf(curbuf, ffname
  2354. #ifdef UNIX
  2355.         , NULL
  2356. #endif
  2357.         );
  2358. }
  2359.  
  2360.     static int
  2361. otherfile_buf(buf, ffname
  2362. #ifdef UNIX
  2363.     , stp
  2364. #endif
  2365.     )
  2366.     buf_T    *buf;
  2367.     char_u    *ffname;
  2368. #ifdef UNIX
  2369.     struct stat    *stp;
  2370. #endif
  2371. {
  2372.     /* no name is different */
  2373.     if (ffname == NULL || *ffname == NUL || buf->b_ffname == NULL)
  2374.     return TRUE;
  2375.     if (fnamecmp(ffname, buf->b_ffname) == 0)
  2376.     return FALSE;
  2377. #ifdef UNIX
  2378.     {
  2379.     struct stat    st;
  2380.  
  2381.     /* If no struct stat given, get it now */
  2382.     if (stp == NULL)
  2383.     {
  2384.         if (buf->b_dev < 0 || mch_stat((char *)ffname, &st) < 0)
  2385.         st.st_dev = (dev_T)-1;
  2386.         stp = &st;
  2387.     }
  2388.     /* Use dev/ino to check if the files are the same, even when the names
  2389.      * are different (possible with links).  Still need to compare the
  2390.      * name above, for when the file doesn't exist yet.
  2391.      * Problem: The dev/ino changes when a file is deleted (and created
  2392.      * again) and remains the same when renamed/moved.  We don't want to
  2393.      * mch_stat() each buffer each time, that would be too slow.  Get the
  2394.      * dev/ino again when they appear to match, but not when they appear
  2395.      * to be different: Could skip a buffer when it's actually the same
  2396.      * file. */
  2397.     if (buf_same_ino(buf, stp))
  2398.     {
  2399.         buf_setino(buf);
  2400.         if (buf_same_ino(buf, stp))
  2401.         return FALSE;
  2402.     }
  2403.     }
  2404. #endif
  2405.     return TRUE;
  2406. }
  2407.  
  2408. #if defined(UNIX) || defined(PROTO)
  2409. /*
  2410.  * Set inode and device number for a buffer.
  2411.  * Must always be called when b_fname is changed!.
  2412.  */
  2413.     void
  2414. buf_setino(buf)
  2415.     buf_T    *buf;
  2416. {
  2417.     struct stat    st;
  2418.  
  2419.     if (buf->b_fname != NULL && mch_stat((char *)buf->b_fname, &st) >= 0)
  2420.     {
  2421.     buf->b_dev = st.st_dev;
  2422.     buf->b_ino = st.st_ino;
  2423.     }
  2424.     else
  2425.     buf->b_dev = -1;
  2426. }
  2427.  
  2428. /*
  2429.  * Return TRUE if dev/ino in buffer "buf" matches with "stp".
  2430.  */
  2431.     static int
  2432. buf_same_ino(buf, stp)
  2433.     buf_T    *buf;
  2434.     struct stat *stp;
  2435. {
  2436.     return (buf->b_dev >= 0
  2437.         && stp->st_dev == buf->b_dev
  2438.         && stp->st_ino == buf->b_ino);
  2439. }
  2440. #endif
  2441.  
  2442.     void
  2443. fileinfo(fullname, shorthelp, dont_truncate)
  2444.     int fullname;
  2445.     int shorthelp;
  2446.     int    dont_truncate;
  2447. {
  2448.     char_u    *name;
  2449.     int        n;
  2450.     char_u    *p;
  2451.     char_u    *buffer;
  2452.  
  2453.     buffer = alloc(IOSIZE);
  2454.     if (buffer == NULL)
  2455.     return;
  2456.  
  2457.     if (fullname > 1)        /* 2 CTRL-G: include buffer number */
  2458.     {
  2459.     sprintf((char *)buffer, "buf %d: ", curbuf->b_fnum);
  2460.     p = buffer + STRLEN(buffer);
  2461.     }
  2462.     else
  2463.     p = buffer;
  2464.  
  2465.     *p++ = '"';
  2466.     if (buf_spname(curbuf) != NULL)
  2467.     STRCPY(p, buf_spname(curbuf));
  2468.     else
  2469.     {
  2470.     if (!fullname && curbuf->b_fname != NULL)
  2471.         name = curbuf->b_fname;
  2472.     else
  2473.         name = curbuf->b_ffname;
  2474.     home_replace(shorthelp ? curbuf : NULL, name, p,
  2475.                       (int)(IOSIZE - (p - buffer)), TRUE);
  2476.     }
  2477.  
  2478.     sprintf((char *)buffer + STRLEN(buffer),
  2479.         "\"%s%s%s%s%s%s",
  2480.         curbufIsChanged() ? (shortmess(SHM_MOD)
  2481.                       ?  " [+]" : _(" [Modified]")) : " ",
  2482.         (curbuf->b_flags & BF_NOTEDITED)
  2483. #ifdef FEAT_QUICKFIX
  2484.             && !bt_dontwrite(curbuf)
  2485. #endif
  2486.                     ? _("[Not edited]") : "",
  2487.         (curbuf->b_flags & BF_NEW)
  2488. #ifdef FEAT_QUICKFIX
  2489.             && !bt_dontwrite(curbuf)
  2490. #endif
  2491.                     ? _("[New file]") : "",
  2492.         (curbuf->b_flags & BF_READERR) ? _("[Read errors]") : "",
  2493.         curbuf->b_p_ro ? (shortmess(SHM_RO) ? "[RO]"
  2494.                               : _("[readonly]")) : "",
  2495.         (curbufIsChanged() || (curbuf->b_flags & BF_WRITE_MASK)
  2496.                               || curbuf->b_p_ro) ?
  2497.                                     " " : "");
  2498.     n = (int)(((long)curwin->w_cursor.lnum * 100L) /
  2499.                         (long)curbuf->b_ml.ml_line_count);
  2500.     if (curbuf->b_ml.ml_flags & ML_EMPTY)
  2501.     {
  2502.     STRCPY(buffer + STRLEN(buffer), _(no_lines_msg));
  2503.     }
  2504. #ifdef FEAT_CMDL_INFO
  2505.     else if (p_ru)
  2506.     {
  2507.     /* Current line and column are already on the screen -- webb */
  2508.     sprintf((char *)buffer + STRLEN(buffer),
  2509.         (curbuf->b_ml.ml_line_count == 1
  2510.              ?  _("1 line --%d%%--") : _("%ld lines --%d%%--")),
  2511.         (long)curbuf->b_ml.ml_line_count,
  2512.         n);
  2513.     }
  2514. #endif
  2515.     else
  2516.     {
  2517.     sprintf((char *)buffer + STRLEN(buffer),
  2518.         _("line %ld of %ld --%d%%-- col "),
  2519.         (long)curwin->w_cursor.lnum,
  2520.         (long)curbuf->b_ml.ml_line_count,
  2521.         n);
  2522.     validate_virtcol();
  2523.     col_print(buffer + STRLEN(buffer),
  2524.            (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1);
  2525.     }
  2526.  
  2527.     (void)append_arg_number(curwin, buffer, !shortmess(SHM_FILE), IOSIZE);
  2528.  
  2529.     if (dont_truncate)
  2530.     {
  2531.     /* Temporarily set msg_scroll to avoid the message being truncated.
  2532.      * First call msg_start() to get the message in the right place. */
  2533.     msg_start();
  2534.     n = msg_scroll;
  2535.     msg_scroll = TRUE;
  2536.     msg(buffer);
  2537.     msg_scroll = n;
  2538.     }
  2539.     else
  2540.     msg_trunc_attr(buffer, FALSE, 0);
  2541.  
  2542.     vim_free(buffer);
  2543. }
  2544.  
  2545.     void
  2546. col_print(buf, col, vcol)
  2547.     char_u  *buf;
  2548.     int        col;
  2549.     int        vcol;
  2550. {
  2551.     if (col == vcol)
  2552.     sprintf((char *)buf, "%d", col);
  2553.     else
  2554.     sprintf((char *)buf, "%d-%d", col, vcol);
  2555. }
  2556.  
  2557. #if defined(FEAT_TITLE) || defined(PROTO)
  2558. /*
  2559.  * put file name in title bar of window and in icon title
  2560.  */
  2561.  
  2562. static char_u *lasttitle = NULL;
  2563. static char_u *lasticon = NULL;
  2564.  
  2565.     void
  2566. maketitle()
  2567. {
  2568.     char_u    *p;
  2569.     char_u    *t_str = NULL;
  2570.     char_u    *i_name;
  2571.     char_u    *i_str = NULL;
  2572.     int        maxlen = 0;
  2573.     int        len;
  2574.     int        mustset;
  2575.     char_u    buf[IOSIZE];
  2576.     int        off;
  2577.  
  2578.     need_maketitle = FALSE;
  2579.     if (!p_title && !p_icon)
  2580.     return;
  2581.  
  2582.     if (p_title)
  2583.     {
  2584.     if (p_titlelen > 0)
  2585.     {
  2586.         maxlen = p_titlelen * Columns / 100;
  2587.         if (maxlen < 10)
  2588.         maxlen = 10;
  2589.     }
  2590.  
  2591.     t_str = buf;
  2592.     if (*p_titlestring != NUL)
  2593.     {
  2594. #ifdef FEAT_STL_OPT
  2595.         if (stl_syntax & STL_IN_TITLE)
  2596.         build_stl_str_hl(curwin, t_str, p_titlestring, 0, maxlen, NULL);
  2597.         else
  2598. #endif
  2599.         t_str = p_titlestring;
  2600.     }
  2601.     else
  2602.     {
  2603.         /* format: "fname + (path) (1 of 2) - VIM" */
  2604.  
  2605.         if (curbuf->b_fname == NULL)
  2606.         STRCPY(buf, _("[No file]"));
  2607.         else
  2608.         {
  2609.         p = transstr(gettail(curbuf->b_fname));
  2610.         STRNCPY(buf, p, IOSIZE - 100);
  2611.         vim_free(p);
  2612.         buf[IOSIZE - 100] = NUL; /* in case it was too long */
  2613.         }
  2614.  
  2615.         switch (bufIsChanged(curbuf)
  2616.             + (curbuf->b_p_ro * 2)
  2617.             + (!curbuf->b_p_ma * 4))
  2618.         {
  2619.         case 1: STRCAT(buf, " +"); break;
  2620.         case 2: STRCAT(buf, " ="); break;
  2621.         case 3: STRCAT(buf, " =+"); break;
  2622.         case 4:
  2623.         case 6: STRCAT(buf, " -"); break;
  2624.         case 5:
  2625.         case 7: STRCAT(buf, " -+"); break;
  2626.         }
  2627.  
  2628.         if (curbuf->b_fname != NULL)
  2629.         {
  2630.         /* Get path of file, replace home dir with ~ */
  2631.         off = (int)STRLEN(buf);
  2632.         buf[off++] = ' ';
  2633.         buf[off++] = '(';
  2634.         home_replace(curbuf, curbuf->b_ffname,
  2635.                            buf + off, IOSIZE - off, TRUE);
  2636. #ifdef BACKSLASH_IN_FILENAME
  2637.         /* avoid "c:/name" to be reduced to "c" */
  2638.         if (isalpha(buf[off]) && buf[off + 1] == ':')
  2639.             off += 2;
  2640. #endif
  2641.         /* remove the file name */
  2642.         p = gettail(buf + off);
  2643.         if (p == buf + off)
  2644.         {
  2645.             /* must be a help buffer */
  2646.             STRCPY(buf + off, _("help"));
  2647.         }
  2648.         else
  2649.         {
  2650.             while (p > buf + off + 1 && vim_ispathsep(p[-1]))
  2651.             --p;
  2652.             *p = NUL;
  2653.         }
  2654.         /* translate unprintable chars */
  2655.         p = transstr(buf + off);
  2656.         STRNCPY(buf + off, p, IOSIZE - off);
  2657.         vim_free(p);
  2658.         buf[IOSIZE - 1] = NUL;  /* in case it was too long */
  2659.         STRCAT(buf, ")");
  2660.         }
  2661.  
  2662.         append_arg_number(curwin, buf, FALSE, IOSIZE);
  2663.  
  2664. #if defined(FEAT_CLIENTSERVER)
  2665.         if (serverName != NULL)
  2666.         {
  2667.         STRCAT(buf, " - ");
  2668.         STRCAT(buf, serverName);
  2669.         }
  2670.         else
  2671. #endif
  2672.         STRCAT(buf, " - VIM");
  2673.  
  2674.         if (maxlen > 0)
  2675.         {
  2676.         /* make it shorter by removing a bit in the middle */
  2677.         len = vim_strsize(buf);
  2678.         if (len > maxlen)
  2679.             trunc_string(buf, buf, maxlen);
  2680.         }
  2681.     }
  2682.     }
  2683.     mustset = ti_change(t_str, &lasttitle);
  2684.  
  2685.     if (p_icon)
  2686.     {
  2687.     i_str = buf;
  2688.     if (*p_iconstring != NUL)
  2689.     {
  2690. #ifdef FEAT_STL_OPT
  2691.         if (stl_syntax & STL_IN_ICON)
  2692.         build_stl_str_hl(curwin, i_str, p_iconstring, 0, 0, NULL);
  2693.         else
  2694. #endif
  2695.         i_str = p_iconstring;
  2696.     }
  2697.     else
  2698.     {
  2699.         if (buf_spname(curbuf) != NULL)
  2700.         i_name = (char_u *)buf_spname(curbuf);
  2701.         else            /* use file name only in icon */
  2702.         i_name = gettail(curbuf->b_ffname);
  2703.         *i_str = NUL;
  2704.         /* Truncate name at 100 chars. */
  2705.         if (STRLEN(i_name) > 100)
  2706.         i_name += STRLEN(i_name) - 100;
  2707.         while (*i_name)
  2708.         STRCAT(i_str, transchar(*i_name++));
  2709.     }
  2710.     }
  2711.  
  2712.     mustset |= ti_change(i_str, &lasticon);
  2713.  
  2714.     if (mustset)
  2715.     resettitle();
  2716. }
  2717.  
  2718. /*
  2719.  * Used for title and icon: Check if "str" differs from "*last".  Set "*last"
  2720.  * from "str" if it does.
  2721.  * Return TRUE when "*last" changed.
  2722.  */
  2723.     static int
  2724. ti_change(str, last)
  2725.     char_u    *str;
  2726.     char_u    **last;
  2727. {
  2728.     if ((str == NULL) != (*last == NULL)
  2729.         || (str != NULL && *last != NULL && STRCMP(str, *last) != 0))
  2730.     {
  2731.     vim_free(*last);
  2732.     if (str == NULL)
  2733.         *last = NULL;
  2734.     else
  2735.         *last = vim_strsave(str);
  2736.     return TRUE;
  2737.     }
  2738.     return FALSE;
  2739. }
  2740.  
  2741. /*
  2742.  * Put current window title back (used after calling a shell)
  2743.  */
  2744.     void
  2745. resettitle()
  2746. {
  2747.     mch_settitle(lasttitle, lasticon);
  2748. }
  2749. #endif /* FEAT_TITLE */
  2750.  
  2751. #if defined(FEAT_STL_OPT) || defined(PROTO)
  2752. /*
  2753.  * Build a string from the status line items in fmt, return length of string.
  2754.  *
  2755.  * Items are drawn interspersed with the text that surrounds it
  2756.  * Specials: %-<wid>(xxx%) => group, %= => middle marker, %< => truncation
  2757.  * Item: %-<minwid>.<maxwid><itemch> All but <itemch> are optional
  2758.  *
  2759.  * if maxlen is not zero, the string will be filled at any middle marker
  2760.  * or truncated if too long, fillchar is used for all whitespace
  2761.  */
  2762.     int
  2763. build_stl_str_hl(wp, out, fmt, fillchar, maxlen, hl)
  2764.     win_T    *wp;
  2765.     char_u    *out;
  2766.     char_u    *fmt;
  2767.     int        fillchar;
  2768.     int        maxlen;
  2769.     struct stl_hlrec *hl;
  2770. {
  2771.     char_u    *p;
  2772.     char_u    *s;
  2773.     char_u    *t;
  2774.     char_u    *linecont;
  2775. #ifdef FEAT_EVAL
  2776.     win_T    *o_curwin;
  2777.     buf_T    *o_curbuf;
  2778. #endif
  2779.     int        empty_line;
  2780.     colnr_T    virtcol;
  2781.     long    l;
  2782.     long    n;
  2783.     int        prevchar_isflag;
  2784.     int        prevchar_isitem;
  2785.     int        itemisflag;
  2786.     char_u    *str;
  2787.     long    num;
  2788.     int        itemcnt;
  2789.     int        curitem;
  2790.     int        groupitem[STL_MAX_ITEM];
  2791.     int        groupdepth;
  2792.     struct stl_item
  2793.     {
  2794.     char_u        *start;
  2795.     int        minwid;
  2796.     int        maxwid;
  2797.     enum
  2798.     {
  2799.         Normal,
  2800.         Empty,
  2801.         Group,
  2802.         Middle,
  2803.         Highlight,
  2804.         Trunc
  2805.     }        type;
  2806.     }        item[STL_MAX_ITEM];
  2807.     int        minwid;
  2808.     int        maxwid;
  2809.     int        zeropad;
  2810.     char_u    base;
  2811.     char_u    opt;
  2812. #define TMPLEN 70
  2813.     char_u    tmp[TMPLEN];
  2814.  
  2815.     if (!fillchar)
  2816.     fillchar = ' ';
  2817.     /*
  2818.      * Get line & check if empty (cursorpos will show "0-1").
  2819.      * If inversion is possible we use it. Else '=' characters are used.
  2820.      */
  2821.     linecont = ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE);
  2822.     empty_line = (*linecont == NUL);
  2823.  
  2824.     groupdepth = 0;
  2825.     p = out;
  2826.     curitem = 0;
  2827.     prevchar_isflag = TRUE;
  2828.     prevchar_isitem = FALSE;
  2829.     for (s = fmt; *s;)
  2830.     {
  2831.     if (*s && *s != '%')
  2832.         prevchar_isflag = prevchar_isitem = FALSE;
  2833.     while (*s && *s != '%')
  2834.         *p++ = *s++;
  2835.     if (!*s)
  2836.         break;
  2837.     s++;
  2838.     if (*s == '%')
  2839.     {
  2840.         *p++ = *s++;
  2841.         prevchar_isflag = prevchar_isitem = FALSE;
  2842.         continue;
  2843.     }
  2844.     if (*s == STL_MIDDLEMARK)
  2845.     {
  2846.         s++;
  2847.         if (groupdepth > 0)
  2848.         continue;
  2849.         item[curitem].type = Middle;
  2850.         item[curitem++].start = p;
  2851.         continue;
  2852.     }
  2853.     if (*s == STL_TRUNCMARK)
  2854.     {
  2855.         s++;
  2856.         item[curitem].type = Trunc;
  2857.         item[curitem++].start = p;
  2858.         continue;
  2859.     }
  2860.     if (*s == ')')
  2861.     {
  2862.         s++;
  2863.         if (groupdepth < 1)
  2864.         continue;
  2865.         groupdepth--;
  2866.         l = (long)(p - item[groupitem[groupdepth]].start);
  2867.         if (curitem > groupitem[groupdepth] + 1
  2868.             && item[groupitem[groupdepth]].minwid == 0)
  2869.         {                /* remove group if all items are empty */
  2870.         for (n = groupitem[groupdepth] + 1; n < curitem; n++)
  2871.             if (item[n].type == Normal)
  2872.             break;
  2873.         if (n == curitem)
  2874.             p = item[groupitem[groupdepth]].start;
  2875.         }
  2876.         if (item[groupitem[groupdepth]].maxwid < l)
  2877.         {                        /* truncate */
  2878.         n = item[groupitem[groupdepth]].maxwid;
  2879.         mch_memmove(item[groupitem[groupdepth]].start,
  2880.                 item[groupitem[groupdepth]].start + l - n,
  2881.                 (size_t)n);
  2882.         t = item[groupitem[groupdepth]].start;
  2883.         *t = '<';
  2884.         l -= n;
  2885.         p -= l;
  2886.         for (n = groupitem[groupdepth] + 1; n < curitem; n++)
  2887.         {
  2888.             item[n].start -= l;
  2889.             if (item[n].start < t)
  2890.             item[n].start = t;
  2891.         }
  2892.         }
  2893.         else if (abs(item[groupitem[groupdepth]].minwid) > l)
  2894.         {                        /* fill */
  2895.         n = item[groupitem[groupdepth]].minwid;
  2896.         if (n < 0)
  2897.         {
  2898.             n = 0 - n;
  2899.             while (l++ < n)
  2900.             *p++ = fillchar;
  2901.         }
  2902.         else
  2903.         {
  2904.             mch_memmove(item[groupitem[groupdepth]].start + n - l,
  2905.                 item[groupitem[groupdepth]].start,
  2906.                 (size_t)l);
  2907.             l = n - l;
  2908.             p += l;
  2909.             for (n = groupitem[groupdepth] + 1; n < curitem; n++)
  2910.             item[n].start += l;
  2911.             for (t = item[groupitem[groupdepth]].start; l > 0; l--)
  2912.             *t++ = fillchar;
  2913.         }
  2914.         }
  2915.         continue;
  2916.     }
  2917.     minwid = 0;
  2918.     maxwid = 50;
  2919.     zeropad = FALSE;
  2920.     l = 1;
  2921.     if (*s == '0')
  2922.     {
  2923.         s++;
  2924.         zeropad = TRUE;
  2925.     }
  2926.     if (*s == '-')
  2927.     {
  2928.         s++;
  2929.         l = -1;
  2930.     }
  2931.     while (*s && isdigit(*s))
  2932.     {
  2933.         minwid *= 10;
  2934.         minwid += *s - '0';
  2935.         s++;
  2936.     }
  2937.     if (*s == STL_HIGHLIGHT)
  2938.     {
  2939.         item[curitem].type = Highlight;
  2940.         item[curitem].start = p;
  2941.         item[curitem].minwid = minwid > 9 ? 1 : minwid;
  2942.         s++;
  2943.         curitem++;
  2944.         continue;
  2945.     }
  2946.     if (*s == '.')
  2947.     {
  2948.         s++;
  2949.         if (isdigit(*s))
  2950.         maxwid = 0;
  2951.         while (*s && isdigit(*s))
  2952.         {
  2953.         maxwid *= 10;
  2954.         maxwid += *s - '0';
  2955.         s++;
  2956.         }
  2957.     }
  2958.     minwid = (minwid > 50 ? 50 : minwid) * l;
  2959.     if (*s == '(')
  2960.     {
  2961.         groupitem[groupdepth++] = curitem;
  2962.         item[curitem].type = Group;
  2963.         item[curitem].start = p;
  2964.         item[curitem].minwid = minwid;
  2965.         item[curitem].maxwid = maxwid;
  2966.         s++;
  2967.         curitem++;
  2968.         continue;
  2969.     }
  2970.     if (vim_strchr(STL_ALL, *s) == NULL)
  2971.     {
  2972.         s++;
  2973.         continue;
  2974.     }
  2975.     opt = *s++;
  2976.  
  2977.     /* OK - now for the real work */
  2978.     base = 'D';
  2979.     itemisflag = FALSE;
  2980.     num = -1;
  2981.     str = NULL;
  2982.     switch (opt)
  2983.     {
  2984.     case STL_FILEPATH:
  2985.     case STL_FULLPATH:
  2986.     case STL_FILENAME:
  2987.         if (buf_spname(wp->w_buffer) != NULL)
  2988.         STRCPY(NameBuff, buf_spname(wp->w_buffer));
  2989.         else
  2990.         {
  2991.         t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname
  2992.                     : wp->w_buffer->b_fname;
  2993.         home_replace(wp->w_buffer, t, NameBuff, MAXPATHL, TRUE);
  2994.         trans_characters(NameBuff, MAXPATHL);
  2995.         }
  2996.         if (opt != STL_FILENAME)
  2997.         str = NameBuff;
  2998.         else
  2999.         str = gettail(NameBuff);
  3000.         break;
  3001.  
  3002.     case STL_VIM_EXPR: /* '{' */
  3003.         itemisflag = TRUE;
  3004.         t = p;
  3005.         while (*s != '}' && *s != NUL)
  3006.         *p++ = *s++;
  3007.         if (*s == NUL)    /* missing '}' */
  3008.         break;
  3009.         s++;
  3010.         *p = 0;
  3011.         p = t;
  3012.  
  3013. #ifdef FEAT_EVAL
  3014.         sprintf((char *)tmp, "%d", curbuf->b_fnum);
  3015.         set_internal_string_var((char_u *)"actual_curbuf", tmp);
  3016.  
  3017.         o_curbuf = curbuf;
  3018.         o_curwin = curwin;
  3019.         curwin = wp;
  3020.         curbuf = wp->w_buffer;
  3021.  
  3022.         str = eval_to_string_safe(p, &t);
  3023.  
  3024.         curwin = o_curwin;
  3025.         curbuf = o_curbuf;
  3026.         do_unlet((char_u *)"g:actual_curbuf");
  3027.  
  3028.         if (str != NULL && *str != 0)
  3029.         {
  3030.         t = str;
  3031.         if (*t == '-')
  3032.             t++;
  3033.         t = skipdigits(t);
  3034.         if (*t == 0)
  3035.         {
  3036.             num = atoi((char *) str);
  3037.             vim_free(str);
  3038.             str = NULL;
  3039.             itemisflag = FALSE;
  3040.         }
  3041.         }
  3042. #endif
  3043.         break;
  3044.  
  3045.     case STL_LINE:
  3046.         num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
  3047.           ? 0L : (long)(wp->w_cursor.lnum);
  3048.         break;
  3049.  
  3050.     case STL_NUMLINES:
  3051.         num = wp->w_buffer->b_ml.ml_line_count;
  3052.         break;
  3053.  
  3054.     case STL_COLUMN:
  3055.         num = !(State & INSERT) && empty_line
  3056.           ? 0 : (int)wp->w_cursor.col + 1;
  3057.         break;
  3058.  
  3059.     case STL_VIRTCOL:
  3060.     case STL_VIRTCOL_ALT:
  3061.         /* In list mode virtcol needs to be recomputed */
  3062.         virtcol = wp->w_virtcol;
  3063.         if (wp->w_p_list && lcs_tab1 == NUL)
  3064.         {
  3065.         wp->w_p_list = FALSE;
  3066.         getvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
  3067.         wp->w_p_list = TRUE;
  3068.         }
  3069.         /* Don't display %V if it's the same as %c. */
  3070.         if (opt == STL_VIRTCOL_ALT
  3071.             && (virtcol == (colnr_T)(!(State & INSERT) && empty_line
  3072.                 ? 0 : (int)wp->w_cursor.col)))
  3073.         break;
  3074.         num = (long)virtcol + 1;
  3075.         break;
  3076.  
  3077.     case STL_PERCENTAGE:
  3078.         num = (int)(((long)wp->w_cursor.lnum * 100L) /
  3079.             (long)wp->w_buffer->b_ml.ml_line_count);
  3080.         break;
  3081.  
  3082.     case STL_ALTPERCENT:
  3083.         str = tmp;
  3084.         get_rel_pos(wp, str);
  3085.         break;
  3086.  
  3087.     case STL_ARGLISTSTAT:
  3088.         tmp[0] = 0;
  3089.         if (append_arg_number(wp, tmp, FALSE, (int)sizeof(tmp)))
  3090.         str = tmp;
  3091.         break;
  3092.  
  3093.     case STL_KEYMAP:
  3094.         if (get_keymap_str(wp, tmp, TMPLEN))
  3095.         str = tmp;
  3096.         break;
  3097.     case STL_PAGENUM:
  3098. #ifdef FEAT_PRINTER
  3099.         num = get_printer_page_num();
  3100. #else
  3101.         num = 0;
  3102. #endif
  3103.         break;
  3104.  
  3105.     case STL_BUFNO:
  3106.         num = wp->w_buffer->b_fnum;
  3107.         break;
  3108.  
  3109.     case STL_OFFSET_X:
  3110.         base = 'X';
  3111.     case STL_OFFSET:
  3112. #ifdef FEAT_BYTEOFF
  3113.         l = ml_find_line_or_offset(wp->w_buffer, wp->w_cursor.lnum, NULL);
  3114.         num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) || l < 0 ?
  3115.           0L : l + 1 + (!(State & INSERT) && empty_line ?
  3116.                 0 : (int)wp->w_cursor.col);
  3117. #endif
  3118.         break;
  3119.  
  3120.     case STL_BYTEVAL_X:
  3121.         base = 'X';
  3122.     case STL_BYTEVAL:
  3123.         if (((State & INSERT) && wp == curwin) || empty_line)
  3124.         num = 0;
  3125.         else
  3126.         {
  3127. #ifdef FEAT_MBYTE
  3128.         num = (*mb_ptr2char)(linecont + wp->w_cursor.col);
  3129. #else
  3130.         num = linecont[wp->w_cursor.col];
  3131. #endif
  3132.         }
  3133.         if (num == NL)
  3134.         num = 0;
  3135.         else if (num == CR && get_fileformat(wp->w_buffer) == EOL_MAC)
  3136.         num = NL;
  3137.         break;
  3138.  
  3139.     case STL_ROFLAG:
  3140.     case STL_ROFLAG_ALT:
  3141.         itemisflag = TRUE;
  3142.         if (wp->w_buffer->b_p_ro)
  3143.         str = (char_u *)((opt == STL_ROFLAG_ALT) ? ",RO" : "[RO]");
  3144.         break;
  3145.  
  3146.     case STL_HELPFLAG:
  3147.     case STL_HELPFLAG_ALT:
  3148.         itemisflag = TRUE;
  3149.         if (wp->w_buffer->b_help)
  3150.         str = (char_u *)((opt == STL_HELPFLAG_ALT) ? ",HLP"
  3151.                                    : _("[help]"));
  3152.         break;
  3153.  
  3154. #ifdef FEAT_AUTOCMD
  3155.     case STL_FILETYPE:
  3156.         if (*wp->w_buffer->b_p_ft != NUL
  3157.             && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 3)
  3158.         {
  3159.         sprintf((char *)tmp, "[%s]", wp->w_buffer->b_p_ft);
  3160.         str = tmp;
  3161.         }
  3162.         break;
  3163.  
  3164.     case STL_FILETYPE_ALT:
  3165.         itemisflag = TRUE;
  3166.         if (*wp->w_buffer->b_p_ft != NUL
  3167.             && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2)
  3168.         {
  3169.         sprintf((char *)tmp, ",%s", wp->w_buffer->b_p_ft);
  3170.         for (t = tmp; *t != 0; t++)
  3171.             *t = TO_UPPER(*t);
  3172.         str = tmp;
  3173.         }
  3174.         break;
  3175. #endif
  3176.  
  3177. #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
  3178.     case STL_PREVIEWFLAG:
  3179.     case STL_PREVIEWFLAG_ALT:
  3180.         itemisflag = TRUE;
  3181.         if (wp->w_p_pvw)
  3182.         str = (char_u *)((opt == STL_PREVIEWFLAG_ALT) ? ",PRV"
  3183.                                 : _("[Preview]"));
  3184.         break;
  3185. #endif
  3186.  
  3187.     case STL_MODIFIED:
  3188.     case STL_MODIFIED_ALT:
  3189.         itemisflag = TRUE;
  3190.         switch ((opt == STL_MODIFIED_ALT)
  3191.             + bufIsChanged(wp->w_buffer) * 2
  3192.             + (!wp->w_buffer->b_p_ma) * 4)
  3193.         {
  3194.         case 2: str = (char_u *)"[+]"; break;
  3195.         case 3: str = (char_u *)",+"; break;
  3196.         case 4: str = (char_u *)"[-]"; break;
  3197.         case 5: str = (char_u *)",-"; break;
  3198.         case 6: str = (char_u *)"[+-]"; break;
  3199.         case 7: str = (char_u *)",+-"; break;
  3200.         }
  3201.         break;
  3202.     }
  3203.  
  3204.     item[curitem].start = p;
  3205.     item[curitem].type = Normal;
  3206.     if (str != NULL && *str)
  3207.     {
  3208.         t = str;
  3209.         if (itemisflag)
  3210.         {
  3211.         if ((t[0] && t[1])
  3212.             && ((!prevchar_isitem && *t == ',')
  3213.                   || (prevchar_isflag && *t == ' ')))
  3214.             t++;
  3215.         prevchar_isflag = TRUE;
  3216.         }
  3217.         l = (long)STRLEN(t);
  3218.         if (l > 0)
  3219.         prevchar_isitem = TRUE;
  3220.         if (l > maxwid)
  3221.         {
  3222.         t += (l - maxwid + 1);
  3223.         *p++ = '<';
  3224.         }
  3225.         if (minwid > 0)
  3226.         {
  3227.         for (; l < minwid; l++)
  3228.             *p++ = fillchar;
  3229.         minwid = 0;
  3230.         }
  3231.         else
  3232.         minwid *= -1;
  3233.         while (*t)
  3234.         {
  3235.         *p++ = *t++;
  3236.         if (p[-1] == ' ')
  3237.             p[-1] = fillchar;
  3238.         }
  3239.         for (; l < minwid; l++)
  3240.         *p++ = fillchar;
  3241.     }
  3242.     else if (num >= 0)
  3243.     {
  3244.         int nbase = (base == 'D' ? 10 : (base == 'O' ? 8 : 16));
  3245.         char_u nstr[20];
  3246.  
  3247.         prevchar_isitem = TRUE;
  3248.         t = nstr;
  3249.         if (opt == STL_VIRTCOL_ALT)
  3250.         {
  3251.         *t++ = '-';
  3252.         minwid--;
  3253.         }
  3254.         *t++ = '%';
  3255.         if (zeropad)
  3256.         *t++ = '0';
  3257.         *t++ = '*';
  3258.         *t++ = nbase == 16 ? base : (nbase == 8 ? 'o' : 'd');
  3259.         *t = 0;
  3260.  
  3261.         for (n = num, l = 1; n >= nbase; n /= nbase)
  3262.         l++;
  3263.         if (opt == STL_VIRTCOL_ALT)
  3264.         l++;
  3265.         if (l > maxwid)
  3266.         {
  3267.         l += 2;
  3268.         n = l - maxwid;
  3269.         while (l-- > maxwid)
  3270.             num /= nbase;
  3271.         *t++ = '>';
  3272.         *t++ = '%';
  3273.         *t = t[-3];
  3274.         *++t = 0;
  3275.         sprintf((char *) p, (char *) nstr, 0, num, n);
  3276.         }
  3277.         else
  3278.         sprintf((char *) p, (char *) nstr, minwid, num);
  3279.         p += STRLEN(p);
  3280.     }
  3281.     else
  3282.         item[curitem].type = Empty;
  3283.  
  3284.     if (opt == STL_VIM_EXPR)
  3285.         vim_free(str);
  3286.  
  3287.     if (num >= 0 || (!itemisflag && str && *str))
  3288.         prevchar_isflag = FALSE;        /* Item not NULL, but not a flag */
  3289.     curitem++;
  3290.     }
  3291.     *p = 0;
  3292.     itemcnt = curitem;
  3293.     num = (long)STRLEN(out);
  3294.  
  3295.     if (maxlen && num > maxlen)
  3296.     {                        /* Apply STL_TRUNC */
  3297.     for (l = 0; l < itemcnt; l++)
  3298.         if (item[l].type == Trunc)
  3299.         break;
  3300.     if (itemcnt == 0)
  3301.         s = out;
  3302.     else
  3303.     {
  3304.         l = l == itemcnt ? 0 : l;
  3305.         s = item[l].start;
  3306.     }
  3307.     if ((int) (s - out) > maxlen)
  3308.     {   /* Truncation mark is beyond max length */
  3309.         s = out + maxlen - 1;
  3310.         for (l = 0; l < itemcnt; l++)
  3311.         if (item[l].start > s)
  3312.             break;
  3313.         *s++ = '>';
  3314.         *s = 0;
  3315.         itemcnt = l;
  3316.     }
  3317.     else
  3318.     {
  3319.         int        shift = num - maxlen;
  3320.  
  3321.         p = s + shift;
  3322.         mch_memmove(s, p, STRLEN(p) + 1);
  3323.         *s = '<';
  3324.         for (; l < itemcnt; l++)
  3325.         {
  3326.         if (item[l].start - shift >= out)
  3327.             item[l].start -= shift;
  3328.         else
  3329.             item[l].start = out;
  3330.         }
  3331.     }
  3332.     num = maxlen;
  3333.     }
  3334.     else if (num < maxlen)
  3335.     {                        /* Apply STL_MIDDLE if any */
  3336.     for (l = 0; l < itemcnt; l++)
  3337.         if (item[l].type == Middle)
  3338.         break;
  3339.     if (l < itemcnt)
  3340.     {
  3341.         p = item[l].start + maxlen - num;
  3342.         mch_memmove(p, item[l].start, STRLEN(item[l].start) + 1);
  3343.         for (s = item[l].start; s < p; s++)
  3344.         *s = fillchar;
  3345.         for (l++; l < itemcnt; l++)
  3346.         item[l].start += maxlen - num;
  3347.         num = maxlen;
  3348.     }
  3349.     }
  3350.  
  3351.     if (hl != NULL)
  3352.     {
  3353.     for (l = 0; l < itemcnt; l++)
  3354.     {
  3355.         if (item[l].type == Highlight)
  3356.         {
  3357.         hl->start = item[l].start;
  3358.         hl->userhl = item[l].minwid;
  3359.         hl++;
  3360.         }
  3361.     }
  3362.     hl->start = NULL;
  3363.     hl->userhl = 0;
  3364.     }
  3365.  
  3366.     return (int)num;
  3367. }
  3368. #endif /* FEAT_STL_OPT */
  3369.  
  3370. #if defined(FEAT_STL_OPT) || defined(FEAT_CMDL_INFO) || defined(PROTO)
  3371. /*
  3372.  * Get relative cursor position in window, in the form 99%, using "Top", "Bot"
  3373.  * or "All" when appropriate.
  3374.  */
  3375.     void
  3376. get_rel_pos(wp, str)
  3377.     win_T    *wp;
  3378.     char_u    *str;
  3379. {
  3380.     long    above; /* number of lines above window */
  3381.     long    below; /* number of lines below window */
  3382.  
  3383.     above = wp->w_topline - 1;
  3384. #ifdef FEAT_DIFF
  3385.     above += diff_check_fill(wp, wp->w_topline) - wp->w_topfill;
  3386. #endif
  3387.     below = wp->w_buffer->b_ml.ml_line_count - wp->w_botline + 1;
  3388.     if (below <= 0)
  3389.     STRCPY(str, above == 0 ? _("All") : _("Bot"));
  3390.     else if (above <= 0)
  3391.     STRCPY(str, _("Top"));
  3392.     else
  3393.     sprintf((char *)str, "%2d%%",
  3394.         (int)(above * 100 / (above + below)));
  3395. }
  3396. #endif
  3397.  
  3398. /*
  3399.  * Append (file 2 of 8) to 'buf', if editing more than one file.
  3400.  * Return TRUE if it was appended.
  3401.  */
  3402.     int
  3403. append_arg_number(wp, buf, add_file, maxlen)
  3404.     win_T    *wp;
  3405.     char_u    *buf;
  3406.     int        add_file;    /* Add "file" before the arg number */
  3407.     int        maxlen;        /* maximum nr of chars in buf or zero*/
  3408. {
  3409.     char_u    *p;
  3410.  
  3411.     if (ARGCOUNT <= 1)        /* nothing to do */
  3412.     return FALSE;
  3413.  
  3414.     p = buf + STRLEN(buf);        /* go to the end of the buffer */
  3415.     if (maxlen && p - buf + 35 >= maxlen) /* getting too long */
  3416.     return FALSE;
  3417.     *p++ = ' ';
  3418.     *p++ = '(';
  3419.     if (add_file)
  3420.     {
  3421.     STRCPY(p, "file ");
  3422.     p += 5;
  3423.     }
  3424.     sprintf((char *)p, wp->w_arg_idx_invalid ? "(%d) of %d)"
  3425.                   : "%d of %d)", wp->w_arg_idx + 1, ARGCOUNT);
  3426.     return TRUE;
  3427. }
  3428.  
  3429. /*
  3430.  * If fname is not a full path, make it a full path.
  3431.  * Returns pointer to allocated memory (NULL for failure).
  3432.  */
  3433.     char_u  *
  3434. fix_fname(fname)
  3435.     char_u  *fname;
  3436. {
  3437.     /*
  3438.      * Force expanding the path always for Unix, because symbolic links may
  3439.      * mess up the full path name, even though it starts with a '/'.
  3440.      * Also expand when there is ".." in the file name, try to remove it,
  3441.      * because "c:/src/../README" is equal to "c:/README".
  3442.      * For MS-Windows also expand names like "longna~1" to "longname".
  3443.      */
  3444. #ifdef UNIX
  3445.     return FullName_save(fname, TRUE);
  3446. #else
  3447.     if (!vim_isAbsName(fname) || strstr((char *)fname, "..") != NULL
  3448. #if defined(MSWIN) || defined(DJGPP)
  3449.         || vim_strchr(fname, '~') != NULL
  3450. #endif
  3451.         )
  3452.     return FullName_save(fname, FALSE);
  3453.  
  3454.     fname = vim_strsave(fname);
  3455.  
  3456. #ifdef USE_FNAME_CASE
  3457. # ifdef USE_LONG_FNAME
  3458.     if (USE_LONG_FNAME)
  3459. # endif
  3460.     {
  3461.     if (fname != NULL)
  3462.         fname_case(fname, 0);    /* set correct case for file name */
  3463.     }
  3464. #endif
  3465.  
  3466.     return fname;
  3467. #endif
  3468. }
  3469.  
  3470. /*
  3471.  * make ffname a full file name, set sfname to ffname if not NULL
  3472.  * ffname becomes a pointer to allocated memory (or NULL).
  3473.  */
  3474.     void
  3475. fname_expand(ffname, sfname)
  3476.     char_u    **ffname;
  3477.     char_u    **sfname;
  3478. {
  3479.     if (*ffname == NULL)    /* if no file name given, nothing to do */
  3480.     return;
  3481.     if (*sfname == NULL)    /* if no short file name given, use ffname */
  3482.     *sfname = *ffname;
  3483.     *ffname = fix_fname(*ffname);   /* expand to full path */
  3484.  
  3485. #ifdef FEAT_SHORTCUT
  3486.     if (!curbuf->b_p_bin)
  3487.     {
  3488.     char_u  *rfname = NULL;
  3489.  
  3490.     /* If the file name is a shortcut file, use the file it links to. */
  3491.     rfname = mch_resolve_shortcut(*ffname);
  3492.     if (rfname)
  3493.     {
  3494.         vim_free(*ffname);
  3495.         *ffname = rfname;
  3496.         *sfname = rfname;
  3497.     }
  3498.     }
  3499. #endif
  3500. }
  3501.  
  3502. /*
  3503.  * Get the file name for an argument list entry.
  3504.  */
  3505.     char_u *
  3506. alist_name(aep)
  3507.     aentry_T    *aep;
  3508. {
  3509.     buf_T    *bp;
  3510.  
  3511.     /* Use the name from the associated buffer if it exists. */
  3512.     bp = buflist_findnr(aep->ae_fnum);
  3513.     if (bp == NULL)
  3514.     return aep->ae_fname;
  3515.     return bp->b_fname;
  3516. }
  3517.  
  3518. #if defined(FEAT_WINDOWS) || defined(PROTO)
  3519. /*
  3520.  * do_arg_all(): Open up to 'count' windows, one for each argument.
  3521.  */
  3522.     void
  3523. do_arg_all(count, forceit)
  3524.     int    count;
  3525.     int    forceit;        /* hide buffers in current windows */
  3526. {
  3527.     int        i;
  3528.     win_T    *wp, *wpnext;
  3529.     char_u    *opened;    /* array of flags for which args are open */
  3530.     int        opened_len;    /* lenght of opened[] */
  3531.     int        use_firstwin = FALSE;    /* use first window for arglist */
  3532.     int        split_ret = OK;
  3533.     int        p_ea_save;
  3534.     alist_T    *alist;        /* argument list to be used */
  3535.     buf_T    *buf;
  3536.  
  3537.     if (ARGCOUNT <= 0)
  3538.     {
  3539.     /* Don't give an error message.  We don't want it when the ":all"
  3540.      * command is in the .vimrc. */
  3541.     return;
  3542.     }
  3543.     setpcmark();
  3544.  
  3545.     opened_len = ARGCOUNT;
  3546.     opened = alloc_clear((unsigned)opened_len);
  3547.     if (opened == NULL)
  3548.     return;
  3549.  
  3550. #ifdef FEAT_GUI
  3551.     need_mouse_correct = TRUE;
  3552. #endif
  3553.  
  3554.     /*
  3555.      * Try closing all windows that are not in the argument list.
  3556.      * Also close windows that are not full width;
  3557.      * When 'hidden' or "forceit" set the buffer becomes hidden.
  3558.      * Windows that have a changed buffer and can't be hidden won't be closed.
  3559.      */
  3560.     for (wp = firstwin; wp != NULL; wp = wpnext)
  3561.     {
  3562.     wpnext = wp->w_next;
  3563.     buf = wp->w_buffer;
  3564.     if (buf->b_ffname == NULL
  3565.         || buf->b_nwindows > 1
  3566. #ifdef FEAT_VERTSPLIT
  3567.         || wp->w_width != Columns
  3568. #endif
  3569.         )
  3570.         i = ARGCOUNT;
  3571.     else
  3572.     {
  3573.         /* check if the buffer in this window is in the arglist */
  3574.         for (i = 0; i < ARGCOUNT; ++i)
  3575.         {
  3576.         if (ARGLIST[i].ae_fnum == buf->b_fnum
  3577.             || fullpathcmp(alist_name(&ARGLIST[i]),
  3578.                           buf->b_ffname, TRUE) & FPC_SAME)
  3579.         {
  3580.             if (i < opened_len)
  3581.             opened[i] = TRUE;
  3582.             if (wp->w_alist != curwin->w_alist)
  3583.             {
  3584.             /* Use the current argument list for all windows
  3585.              * containing a file from it. */
  3586.             alist_unlink(wp->w_alist);
  3587.             wp->w_alist = curwin->w_alist;
  3588.             ++wp->w_alist->al_refcount;
  3589.             }
  3590.             break;
  3591.         }
  3592.         }
  3593.     }
  3594.     wp->w_arg_idx = i;
  3595.  
  3596.     if (i == ARGCOUNT)        /* close this window */
  3597.     {
  3598.         if (P_HID(buf) || forceit || buf->b_nwindows > 1
  3599.                             || !bufIsChanged(buf))
  3600.         {
  3601.         /* If the buffer was changed, and we would like to hide it,
  3602.          * try autowriting. */
  3603.         if (!P_HID(buf) && buf->b_nwindows <= 1 && bufIsChanged(buf))
  3604.         {
  3605.             (void)autowrite(buf, FALSE);
  3606. #ifdef FEAT_AUTOCMD
  3607.             /* check if autocommands removed the window */
  3608.             if (!win_valid(wp) || !buf_valid(buf))
  3609.             {
  3610.             wpnext = firstwin;    /* start all over... */
  3611.             continue;
  3612.             }
  3613. #endif
  3614.         }
  3615. #ifdef FEAT_WINDOWS
  3616.         if (firstwin == lastwin)    /* can't close last window */
  3617. #endif
  3618.             use_firstwin = TRUE;
  3619. #ifdef FEAT_WINDOWS
  3620.         else
  3621.         {
  3622.             win_close(wp, !P_HID(buf) && !bufIsChanged(buf));
  3623. # ifdef FEAT_AUTOCMD
  3624.             /* check if autocommands removed the next window */
  3625.             if (!win_valid(wpnext))
  3626.             wpnext = firstwin;    /* start all over... */
  3627. # endif
  3628.         }
  3629. #endif
  3630.         }
  3631.     }
  3632.     }
  3633.  
  3634.     /*
  3635.      * Open a window for files in the argument list that don't have one.
  3636.      * ARGCOUNT may change while doing this, because of autocommands.
  3637.      */
  3638.     if (count > ARGCOUNT || count <= 0)
  3639.     count = ARGCOUNT;
  3640.  
  3641.     /* Autocommands may do anything to the argument list.  Make sure it's not
  3642.      * freed while we are working here by "locking" it.  We still have to
  3643.      * watch out for its size to be changed. */
  3644.     alist = curwin->w_alist;
  3645.     ++alist->al_refcount;
  3646.  
  3647. #ifdef FEAT_AUTOCMD
  3648.     /* Don't execute Win/Buf Enter/Leave autocommands here. */
  3649.     ++autocmd_no_enter;
  3650.     ++autocmd_no_leave;
  3651. #endif
  3652.     win_enter(lastwin, FALSE);
  3653.     for (i = 0; i < count && i < alist->al_ga.ga_len && !got_int; ++i)
  3654.     {
  3655.     if (alist == &global_alist && i == global_alist.al_ga.ga_len - 1)
  3656.         arg_had_last = TRUE;
  3657.     if (i < opened_len && opened[i])
  3658.     {
  3659.         /* Move the already present window to below the current window */
  3660.         if (curwin->w_arg_idx != i)
  3661.         {
  3662.         for (wpnext = firstwin; wpnext != NULL; wpnext = wpnext->w_next)
  3663.         {
  3664.             if (wpnext->w_arg_idx == i)
  3665.             {
  3666.             win_move_after(wpnext, curwin);
  3667.             break;
  3668.             }
  3669.         }
  3670.         }
  3671.     }
  3672.     else if (split_ret == OK)
  3673.     {
  3674.         if (!use_firstwin)        /* split current window */
  3675.         {
  3676.         p_ea_save = p_ea;
  3677.         p_ea = TRUE;        /* use space from all windows */
  3678.         split_ret = win_split(0, WSP_ROOM | WSP_BELOW);
  3679.         p_ea = p_ea_save;
  3680.         if (split_ret == FAIL)
  3681.             continue;
  3682.         }
  3683. #ifdef FEAT_AUTOCMD
  3684.         else    /* first window: do autocmd for leaving this buffer */
  3685.         --autocmd_no_leave;
  3686. #endif
  3687.  
  3688.         /*
  3689.          * edit file i
  3690.          */
  3691.         curwin->w_arg_idx = i;
  3692.         (void)do_ecmd(0, alist_name(&AARGLIST(alist)[i]), NULL, NULL,
  3693.               ECMD_ONE,
  3694.               ((P_HID(curwin->w_buffer)
  3695.                || bufIsChanged(curwin->w_buffer)) ? ECMD_HIDE : 0)
  3696.                                    + ECMD_OLDBUF);
  3697. #ifdef FEAT_AUTOCMD
  3698.         if (use_firstwin)
  3699.         ++autocmd_no_leave;
  3700. #endif
  3701.         use_firstwin = FALSE;
  3702.     }
  3703.     ui_breakcheck();
  3704.     }
  3705.  
  3706.     /* Remove the "lock" on the argument list. */
  3707.     alist_unlink(alist);
  3708.  
  3709. #ifdef FEAT_AUTOCMD
  3710.     --autocmd_no_enter;
  3711. #endif
  3712.     win_enter(firstwin, FALSE);            /* back to first window */
  3713. #ifdef FEAT_AUTOCMD
  3714.     --autocmd_no_leave;
  3715. #endif
  3716. }
  3717.  
  3718. # if defined(FEAT_LISTCMDS) || defined(PROTO)
  3719. /*
  3720.  * Open a window for a number of buffers.
  3721.  */
  3722.     void
  3723. ex_buffer_all(eap)
  3724.     exarg_T    *eap;
  3725. {
  3726.     buf_T    *buf;
  3727.     win_T    *wp, *wpnext;
  3728.     int        split_ret = OK;
  3729.     int        p_ea_save;
  3730.     int        open_wins = 0;
  3731.     int        r;
  3732.     int        count;        /* Maximum number of windows to open. */
  3733.     int        all;        /* When TRUE also load inactive buffers. */
  3734.  
  3735.     if (eap->addr_count == 0)    /* make as many windows as possible */
  3736.     count = 9999;
  3737.     else
  3738.     count = eap->line2;    /* make as many windows as specified */
  3739.     if (eap->cmdidx == CMD_unhide || eap->cmdidx == CMD_sunhide)
  3740.     all = FALSE;
  3741.     else
  3742.     all = TRUE;
  3743.  
  3744.     setpcmark();
  3745.  
  3746. #ifdef FEAT_GUI
  3747.     need_mouse_correct = TRUE;
  3748. #endif
  3749.  
  3750.     /*
  3751.      * Close superfluous windows (two windows for the same buffer).
  3752.      * Also close windows that are not full-width.
  3753.      */
  3754.     for (wp = firstwin; wp != NULL; wp = wpnext)
  3755.     {
  3756.     wpnext = wp->w_next;
  3757.     if (wp->w_buffer->b_nwindows > 1
  3758. #ifdef FEAT_VERTSPLIT
  3759.         || (cmdmod.split & WSP_VERT)
  3760.               ? wp->w_height + wp->w_status_height < Rows - p_ch
  3761.               : wp->w_width != Columns
  3762. #endif
  3763.         )
  3764.     {
  3765.         win_close(wp, FALSE);
  3766. #ifdef FEAT_AUTOCMD
  3767.         wpnext = firstwin;        /* just in case an autocommand does
  3768.                        something strange with windows */
  3769.         open_wins = 0;
  3770. #endif
  3771.     }
  3772.     else
  3773.         ++open_wins;
  3774.     }
  3775.  
  3776.     /*
  3777.      * Go through the buffer list.  When a buffer doesn't have a window yet,
  3778.      * open one.  Otherwise move the window to the right position.
  3779.      * Watch out for autocommands that delete buffers or windows!
  3780.      */
  3781. #ifdef FEAT_AUTOCMD
  3782.     /* Don't execute Win/Buf Enter/Leave autocommands here. */
  3783.     ++autocmd_no_enter;
  3784. #endif
  3785.     win_enter(lastwin, FALSE);
  3786. #ifdef FEAT_AUTOCMD
  3787.     ++autocmd_no_leave;
  3788. #endif
  3789.     for (buf = firstbuf; buf != NULL && open_wins < count; buf = buf->b_next)
  3790.     {
  3791.     /* Check if this buffer needs a window */
  3792.     if ((!all && buf->b_ml.ml_mfp == NULL) || !buf->b_p_bl)
  3793.         continue;
  3794.  
  3795.     /* Check if this buffer already has a window */
  3796.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  3797.         if (wp->w_buffer == buf)
  3798.         break;
  3799.     /* If the buffer already has a window, move it */
  3800.     if (wp != NULL)
  3801.         win_move_after(wp, curwin);
  3802.     else if (split_ret == OK)
  3803.     {
  3804.         /* Split the window and put the buffer in it */
  3805.         p_ea_save = p_ea;
  3806.         p_ea = TRUE;        /* use space from all windows */
  3807.         split_ret = win_split(0, WSP_ROOM | WSP_BELOW);
  3808.         ++open_wins;
  3809.         p_ea = p_ea_save;
  3810.         if (split_ret == FAIL)
  3811.         continue;
  3812.  
  3813.         /* Open the buffer in this window. */
  3814. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  3815.         swap_exists_action = SEA_DIALOG;
  3816. #endif
  3817.         set_curbuf(buf, DOBUF_GOTO);
  3818. #ifdef FEAT_AUTOCMD
  3819.         if (!buf_valid(buf))    /* autocommands deleted the buffer!!! */
  3820.         {
  3821. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  3822.         swap_exists_action = SEA_NONE;
  3823. #endif
  3824.         break;
  3825.         }
  3826. #endif
  3827. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  3828.         if (swap_exists_action == SEA_QUIT)
  3829.         {
  3830.         /* User selected Quit at ATTENTION prompt; close this window. */
  3831.         win_close(curwin, TRUE);
  3832.         --open_wins;
  3833.         swap_exists_action = SEA_NONE;
  3834.         }
  3835.         else
  3836.         handle_swap_exists(NULL);
  3837. #endif
  3838.     }
  3839.  
  3840.     ui_breakcheck();
  3841.     if (got_int)
  3842.     {
  3843.         (void)vgetc();    /* only break the file loading, not the rest */
  3844.         break;
  3845.     }
  3846.     }
  3847. #ifdef FEAT_AUTOCMD
  3848.     --autocmd_no_enter;
  3849. #endif
  3850.     win_enter(firstwin, FALSE);        /* back to first window */
  3851. #ifdef FEAT_AUTOCMD
  3852.     --autocmd_no_leave;
  3853. #endif
  3854.  
  3855.     /*
  3856.      * Close superfluous windows.
  3857.      */
  3858.     for (wp = lastwin; open_wins > count; )
  3859.     {
  3860.     r = (P_HID(wp->w_buffer) || !bufIsChanged(wp->w_buffer)
  3861.                      || autowrite(wp->w_buffer, FALSE) == OK);
  3862. #ifdef FEAT_AUTOCMD
  3863.     if (!win_valid(wp))
  3864.     {
  3865.         /* BufWrite Autocommands made the window invalid, start over */
  3866.         wp = lastwin;
  3867.     }
  3868.     else
  3869. #endif
  3870.         if (r)
  3871.     {
  3872.         win_close(wp, !P_HID(wp->w_buffer));
  3873.         --open_wins;
  3874.         wp = lastwin;
  3875.     }
  3876.     else
  3877.     {
  3878.         wp = wp->w_prev;
  3879.         if (wp == NULL)
  3880.         break;
  3881.     }
  3882.     }
  3883. }
  3884. # endif /* FEAT_LISTCMDS */
  3885.  
  3886. #endif /* FEAT_WINDOWS */
  3887.  
  3888. /*
  3889.  * do_modelines() - process mode lines for the current file
  3890.  *
  3891.  * Returns immediately if the "ml" option isn't set.
  3892.  */
  3893. static int  chk_modeline __ARGS((linenr_T));
  3894.  
  3895.     void
  3896. do_modelines()
  3897. {
  3898.     linenr_T        lnum;
  3899.     int            nmlines;
  3900.     static int        entered = 0;
  3901.  
  3902.     if (!curbuf->b_p_ml || (nmlines = (int)p_mls) == 0)
  3903.     return;
  3904.  
  3905.     /* Disallow recursive entry here.  Can happen when executing a modeline
  3906.      * triggers an autocommand, which reloads modelines with a ":do". */
  3907.     if (entered)
  3908.     return;
  3909.  
  3910.     ++entered;
  3911.     for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count && lnum <= nmlines;
  3912.                                        ++lnum)
  3913.     if (chk_modeline(lnum) == FAIL)
  3914.         nmlines = 0;
  3915.  
  3916.     for (lnum = curbuf->b_ml.ml_line_count; lnum > 0 && lnum > nmlines
  3917.                && lnum > curbuf->b_ml.ml_line_count - nmlines; --lnum)
  3918.     if (chk_modeline(lnum) == FAIL)
  3919.         nmlines = 0;
  3920.     --entered;
  3921. }
  3922.  
  3923. #include "version.h"        /* for version number */
  3924.  
  3925. /*
  3926.  * chk_modeline() - check a single line for a mode string
  3927.  * Return FAIL if an error encountered.
  3928.  */
  3929.     static int
  3930. chk_modeline(lnum)
  3931.     linenr_T    lnum;
  3932. {
  3933.     char_u    *s;
  3934.     char_u    *e;
  3935.     char_u    *linecopy;        /* local copy of any modeline found */
  3936.     int        prev;
  3937.     int        vers;
  3938.     int        end;
  3939.     int        retval = OK;
  3940.     char_u    *save_sourcing_name;
  3941.     linenr_T    save_sourcing_lnum;
  3942. #ifdef FEAT_EVAL
  3943.     scid_T    save_SID;
  3944. #endif
  3945.  
  3946.     prev = -1;
  3947.     for (s = ml_get(lnum); *s != NUL; ++s)
  3948.     {
  3949.     if (prev == -1 || vim_isspace(prev))
  3950.     {
  3951.         if ((prev != -1 && STRNCMP(s, "ex:", (size_t)3) == 0)
  3952.             || STRNCMP(s, "vi:", (size_t)3) == 0)
  3953.         break;
  3954.         if (STRNCMP(s, "vim", 3) == 0)
  3955.         {
  3956.         if (s[3] == '<' || s[3] == '=' || s[3] == '>')
  3957.             e = s + 4;
  3958.         else
  3959.             e = s + 3;
  3960.         vers = getdigits(&e);
  3961.         if (*e == ':'
  3962.             && (s[3] == ':'
  3963.                 || (VIM_VERSION_100 >= vers && isdigit(s[3]))
  3964.                 || (VIM_VERSION_100 < vers && s[3] == '<')
  3965.                 || (VIM_VERSION_100 > vers && s[3] == '>')
  3966.                 || (VIM_VERSION_100 == vers && s[3] == '=')))
  3967.             break;
  3968.         }
  3969.     }
  3970.     prev = *s;
  3971.     }
  3972.  
  3973.     if (*s)
  3974.     {
  3975.     do                /* skip over "ex:", "vi:" or "vim:" */
  3976.         ++s;
  3977.     while (s[-1] != ':');
  3978.  
  3979.     s = linecopy = vim_strsave(s);    /* copy the line, it will change */
  3980.     if (linecopy == NULL)
  3981.         return FAIL;
  3982.  
  3983.     save_sourcing_lnum = sourcing_lnum;
  3984.     save_sourcing_name = sourcing_name;
  3985.     sourcing_lnum = lnum;        /* prepare for emsg() */
  3986.     sourcing_name = (char_u *)"modelines";
  3987.  
  3988.     end = FALSE;
  3989.     while (end == FALSE)
  3990.     {
  3991.         s = skipwhite(s);
  3992.         if (*s == NUL)
  3993.         break;
  3994.  
  3995.         /*
  3996.          * Find end of set command: ':' or end of line.
  3997.          * Skip over "\:", replacing it with ":".
  3998.          */
  3999.         for (e = s; *e != ':' && *e != NUL; ++e)
  4000.         if (e[0] == '\\' && e[1] == ':')
  4001.             STRCPY(e, e + 1);
  4002.         if (*e == NUL)
  4003.         end = TRUE;
  4004.  
  4005.         /*
  4006.          * If there is a "set" command, require a terminating ':' and
  4007.          * ignore the stuff after the ':'.
  4008.          * "vi:set opt opt opt: foo" -- foo not interpreted
  4009.          * "vi:opt opt opt: foo" -- foo interpreted
  4010.          */
  4011.         if (STRNCMP(s, "set ", (size_t)4) == 0)
  4012.         {
  4013.         if (*e != ':')        /* no terminating ':'? */
  4014.             break;
  4015.         end = TRUE;
  4016.         s += 4;
  4017.         }
  4018.         *e = NUL;            /* truncate the set command */
  4019.  
  4020.         if (*s != NUL)        /* skip over an empty "::" */
  4021.         {
  4022. #ifdef FEAT_EVAL
  4023.         save_SID = current_SID;
  4024.         current_SID = SID_MODELINE;
  4025. #endif
  4026.         retval = do_set(s, OPT_MODELINE | OPT_LOCAL);
  4027. #ifdef FEAT_EVAL
  4028.         current_SID = save_SID;
  4029. #endif
  4030.         if (retval == FAIL)        /* stop if error found */
  4031.             break;
  4032.         }
  4033.         s = e + 1;            /* advance to next part */
  4034.     }
  4035.  
  4036.     sourcing_lnum = save_sourcing_lnum;
  4037.     sourcing_name = save_sourcing_name;
  4038.  
  4039.     vim_free(linecopy);
  4040.     }
  4041.     return retval;
  4042. }
  4043.  
  4044. #ifdef FEAT_VIMINFO
  4045.     int
  4046. read_viminfo_bufferlist(virp, writing)
  4047.     vir_T    *virp;
  4048.     int        writing;
  4049. {
  4050.     char_u    *tab;
  4051.     linenr_T    lnum;
  4052.     colnr_T    col;
  4053.     buf_T    *buf;
  4054.     char_u    *sfname;
  4055.     char_u    *xline;
  4056.  
  4057.     /* Handle long line and escaped characters. */
  4058.     xline = viminfo_readstring(virp, 1, FALSE);
  4059.  
  4060.     /* don't read in if there are files on the command-line or if writing: */
  4061.     if (xline != NULL && !writing && ARGCOUNT == 0
  4062.                        && find_viminfo_parameter('%') != NULL)
  4063.     {
  4064.     /* Format is: <fname> Tab <lnum> Tab <col>.
  4065.      * Watch out for a Tab in the file name, work from the end. */
  4066.     lnum = 0;
  4067.     col = 0;
  4068.     tab = vim_strrchr(xline, '\t');
  4069.     if (tab != NULL)
  4070.     {
  4071.         *tab++ = '\0';
  4072.         col = atoi((char *)tab);
  4073.         tab = vim_strrchr(xline, '\t');
  4074.         if (tab != NULL)
  4075.         {
  4076.         *tab++ = '\0';
  4077.         lnum = atol((char *)tab);
  4078.         }
  4079.     }
  4080.  
  4081.     /* Expand "~/" in the file name at "line + 1" to a full path.
  4082.      * Then try shortening it by comparing with the current directory */
  4083.     expand_env(xline, NameBuff, MAXPATHL);
  4084.     mch_dirname(IObuff, IOSIZE);
  4085.     sfname = shorten_fname(NameBuff, IObuff);
  4086.     if (sfname == NULL)
  4087.         sfname = NameBuff;
  4088.  
  4089.     buf = buflist_new(NameBuff, sfname, (linenr_T)0, BLN_LISTED);
  4090.     if (buf != NULL)    /* just in case... */
  4091.     {
  4092.         buf->b_last_cursor.lnum = lnum;
  4093.         buf->b_last_cursor.col = col;
  4094.         buflist_setfpos(buf, curwin, lnum, col, FALSE);
  4095.     }
  4096.     }
  4097.     vim_free(xline);
  4098.  
  4099.     return viminfo_readline(virp);
  4100. }
  4101.  
  4102.     void
  4103. write_viminfo_bufferlist(fp)
  4104.     FILE    *fp;
  4105. {
  4106.     buf_T    *buf;
  4107. #ifdef FEAT_WINDOWS
  4108.     win_T    *win;
  4109. #endif
  4110.     char_u    *line;
  4111.  
  4112.     if (find_viminfo_parameter('%') == NULL)
  4113.     return;
  4114.  
  4115.     /* Allocate room for the file name, lnum and col. */
  4116.     line = alloc(MAXPATHL + 30);
  4117.     if (line == NULL)
  4118.     return;
  4119.  
  4120. #ifdef FEAT_WINDOWS
  4121.     for (win = firstwin; win != NULL; win = win->w_next)
  4122.     set_last_cursor(win);
  4123. #else
  4124.     set_last_cursor(curwin);
  4125. #endif
  4126.  
  4127.     fprintf(fp, _("\n# Buffer list:\n"));
  4128.     for (buf = firstbuf; buf != NULL ; buf = buf->b_next)
  4129.     {
  4130.     if (buf->b_fname == NULL
  4131.         || !buf->b_p_bl
  4132. #ifdef FEAT_QUICKFIX
  4133.         || bt_quickfix(buf)
  4134. #endif
  4135.         || removable(buf->b_ffname))
  4136.         continue;
  4137.  
  4138.     putc('%', fp);
  4139.     home_replace(NULL, buf->b_ffname, line, MAXPATHL, TRUE);
  4140.     sprintf((char *)line + STRLEN(line), "\t%ld\t%d",
  4141.             (long)buf->b_last_cursor.lnum,
  4142.             buf->b_last_cursor.col);
  4143.     viminfo_writestring(fp, line);
  4144.     }
  4145.     vim_free(line);
  4146. }
  4147. #endif
  4148.  
  4149.  
  4150. /*
  4151.  * Return special buffer name.
  4152.  * Returns NULL when the buffer has a normal file name.
  4153.  */
  4154.     char *
  4155. buf_spname(buf)
  4156.     buf_T    *buf;
  4157. {
  4158. #if defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS)
  4159.     if (bt_quickfix(buf))
  4160.     return _("[Error List]");
  4161. #endif
  4162. #ifdef FEAT_QUICKFIX
  4163.     /* There is no _file_ when 'buftype' is "nofile", b_sfname
  4164.      * contains the name as specified by the user */
  4165.     if (bt_nofile(buf))
  4166.     {
  4167.     if (buf->b_sfname != NULL)
  4168.         return (char *)buf->b_sfname;
  4169.     return "[Scratch]";
  4170.     }
  4171. #endif
  4172.     if (buf->b_fname == NULL)
  4173.     return _("[No File]");
  4174.     return NULL;
  4175. }
  4176.  
  4177.  
  4178. #if defined(FEAT_SIGNS) || defined(PROTO)
  4179.  
  4180. static void insert_sign __ARGS((buf_T *buf, signlist_T *prev, signlist_T *next, int id, linenr_T lnum, int typenr));
  4181.  
  4182. /*
  4183.  * Insert the sign into the signlist.
  4184.  */
  4185.     static void
  4186. insert_sign(buf, prev, next, id, lnum, typenr)
  4187.     buf_T    *buf;        /* buffer to store sign in */
  4188.     signlist_T    *prev;        /* previous sign entry */
  4189.     signlist_T    *next;        /* next sign entry */
  4190.     int        id;        /* sign ID */
  4191.     linenr_T    lnum;        /* line number which gets the mark */
  4192.     int        typenr;        /* typenr of sign we are adding */
  4193. {
  4194.     signlist_T    *newsign;
  4195.  
  4196.     newsign = (signlist_T *)lalloc((long_u)sizeof(signlist_T), FALSE);
  4197.     if (newsign != NULL)
  4198.     {
  4199.     newsign->id = id;
  4200.     newsign->lnum = lnum;
  4201.     newsign->typenr = typenr;
  4202.     newsign->next = next;
  4203.  
  4204.     if (prev == NULL)
  4205.     {
  4206.         /* When adding first sign need to redraw the windows to create the
  4207.          * column for signs. */
  4208.         if (buf->b_signlist == NULL)
  4209.         {
  4210.         redraw_buf_later(buf, NOT_VALID);
  4211.         changed_cline_bef_curs();
  4212.         }
  4213.  
  4214.         /* first sign in signlist */
  4215.         buf->b_signlist = newsign;
  4216.     }
  4217.     else
  4218.         prev->next = newsign;
  4219.     }
  4220. }
  4221.  
  4222. /*
  4223.  * Add the sign into the signlist. Find the right spot to do it though.
  4224.  */
  4225.     int
  4226. buf_addsign(buf, id, lnum, typenr)
  4227.     buf_T    *buf;        /* buffer to store sign in */
  4228.     int        id;        /* sign ID */
  4229.     linenr_T    lnum;        /* line number which gets the mark */
  4230.     int        typenr;        /* typenr of sign we are adding */
  4231. {
  4232.     signlist_T    *sign;        /* a sign in the signlist */
  4233.     signlist_T    *prev;        /* the previous sign */
  4234.  
  4235.     prev = NULL;
  4236.     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
  4237.     {
  4238.     if (lnum == sign->lnum && id == sign->id)
  4239.     {
  4240.         sign->typenr = typenr;
  4241.         return sign->lnum;
  4242.     }
  4243.     else if (id < 0 && lnum < sign->lnum)
  4244.     {
  4245.         insert_sign(buf, prev, sign, id, lnum, typenr);
  4246.         return lnum;
  4247.     }
  4248.     prev = sign;
  4249.     }
  4250.     insert_sign(buf, prev, NULL, id, lnum, typenr);
  4251.  
  4252.     return lnum;
  4253. }
  4254.  
  4255.     int
  4256. buf_change_sign_type(buf, markId, typenr)
  4257.     buf_T    *buf;        /* buffer to store sign in */
  4258.     int        markId;        /* sign ID */
  4259.     int        typenr;        /* typenr of sign we are adding */
  4260. {
  4261.     signlist_T    *sign;        /* a sign in the signlist */
  4262.  
  4263.     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
  4264.     {
  4265.     if (sign->id == markId)
  4266.     {
  4267.         sign->typenr = typenr;
  4268.         return sign->lnum;
  4269.     }
  4270.     }
  4271.  
  4272.     return 0;
  4273. }
  4274.  
  4275.     int_u
  4276. buf_getsigntype(buf, lnum)
  4277.     buf_T    *buf;
  4278.     linenr_T    lnum;
  4279. {
  4280.     signlist_T    *sign;        /* a sign in a b_signlist */
  4281.  
  4282.     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
  4283.     if (sign->lnum == lnum)
  4284.         return sign->typenr;
  4285.     return 0;
  4286. }
  4287.  
  4288.  
  4289.     linenr_T
  4290. buf_delsign(buf, id)
  4291.     buf_T    *buf;        /* buffer sign is stored in */
  4292.     int        id;        /* sign id */
  4293. {
  4294.     signlist_T    **lastp;    /* pointer to pointer to current sign */
  4295.     signlist_T    *sign;        /* a sign in a b_signlist */
  4296.     signlist_T    *next;        /* the next sign in a b_signlist */
  4297.     linenr_T    lnum;        /* line number whose sign was deleted */
  4298.  
  4299.     lastp = &buf->b_signlist;
  4300.     lnum = 0;
  4301.     for (sign = buf->b_signlist; sign != NULL; sign = next)
  4302.     {
  4303.     next = sign->next;
  4304.     if (sign->id == id)
  4305.     {
  4306.         *lastp = next;
  4307.         lnum = sign->lnum;
  4308.         vim_free(sign);
  4309.         break;
  4310.     }
  4311.     else
  4312.         lastp = &sign->next;
  4313.     }
  4314.  
  4315.     /* When deleted the last sign need to redraw the windows to remove the
  4316.      * sign column. */
  4317.     if (buf->b_signlist == NULL)
  4318.     {
  4319.     redraw_buf_later(buf, NOT_VALID);
  4320.     changed_cline_bef_curs();
  4321.     }
  4322.  
  4323.     return lnum;
  4324. }
  4325.  
  4326.  
  4327. /*
  4328.  * Find the line number of the sign with the requested id. If the sign does
  4329.  * not exist, return 0 as the line number. This will still let the correct file
  4330.  * get loaded.
  4331.  */
  4332.     int
  4333. buf_findsign(buf, id)
  4334.     buf_T    *buf;        /* buffer to store sign in */
  4335.     int        id;        /* sign ID */
  4336. {
  4337.     signlist_T    *sign;        /* a sign in the signlist */
  4338.  
  4339.     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
  4340.     if (sign->id == id)
  4341.         return sign->lnum;
  4342.  
  4343.     return 0;
  4344. }
  4345.  
  4346.     int
  4347. buf_findsign_id(buf, lnum)
  4348.     buf_T    *buf;        /* buffer whose sign we are searching for */
  4349.     linenr_T    lnum;        /* line number of sign */
  4350. {
  4351.     signlist_T    *sign;        /* a sign in the signlist */
  4352.  
  4353.     for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
  4354.     if (sign->lnum == lnum)
  4355.         return sign->id;
  4356.  
  4357.     return 0;
  4358. }
  4359.  
  4360.  
  4361.     void
  4362. buf_delete_all_signs()
  4363. {
  4364.     buf_T    *buf;        /* buffer we are checking for signs */
  4365.     signlist_T    *sign;        /* a sign in a b_signlist */
  4366.     signlist_T    *next;        /* the next sign in a b_signlist */
  4367.  
  4368.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  4369.     if (buf->b_signlist != NULL)
  4370.     {
  4371.         /* Need to redraw the windows to remove the sign column. */
  4372.         redraw_buf_later(buf, NOT_VALID);
  4373.         for (sign = buf->b_signlist; sign != NULL; sign = next)
  4374.         {
  4375.         next = sign->next;
  4376.         vim_free(sign);
  4377.         }
  4378.         buf->b_signlist = NULL;
  4379.     }
  4380. }
  4381.  
  4382. /*
  4383.  * List placed signs for "rbuf".  If "rbuf" is NULL do it for all buffers.
  4384.  */
  4385.     void
  4386. sign_list_placed(rbuf)
  4387.     buf_T    *rbuf;
  4388. {
  4389.     buf_T    *buf;
  4390.     signlist_T    *p;
  4391.     char    lbuf[BUFSIZ];
  4392.  
  4393.     MSG_PUTS_TITLE(_("\n--- Signs ---"));
  4394.     msg_putchar('\n');
  4395.     if (rbuf == NULL)
  4396.     buf = firstbuf;
  4397.     else
  4398.     buf = rbuf;
  4399.     while (buf != NULL)
  4400.     {
  4401.     if (buf->b_signlist != NULL)
  4402.     {
  4403.         sprintf(lbuf, _("Signs for %s:"), buf->b_fname);
  4404.         MSG_PUTS_ATTR(lbuf, hl_attr(HLF_D));
  4405.         msg_putchar('\n');
  4406.     }
  4407.     for (p = buf->b_signlist; p != NULL; p = p->next)
  4408.     {
  4409.         sprintf(lbuf, _("    line=%ld  id=%d  name=%s"),
  4410.                (long)p->lnum, p->id, sign_typenr2name(p->typenr));
  4411.         MSG_PUTS(lbuf);
  4412.         msg_putchar('\n');
  4413.     }
  4414.     if (rbuf != NULL)
  4415.         break;
  4416.     buf = buf->b_next;
  4417.     }
  4418. }
  4419.  
  4420. /*
  4421.  * Adjust a placed sign for inserted/deleted lines.
  4422.  */
  4423.     void
  4424. sign_mark_adjust(line1, line2, amount, amount_after)
  4425.     linenr_T    line1;
  4426.     linenr_T    line2;
  4427.     long    amount;
  4428.     long    amount_after;
  4429. {
  4430.     signlist_T    *sign;        /* a sign in a b_signlist */
  4431.  
  4432.     for (sign = curbuf->b_signlist; sign != NULL; sign = sign->next)
  4433.     {
  4434.     if (sign->lnum >= line1 && sign->lnum <= line2)
  4435.     {
  4436.         if (amount == MAXLNUM)
  4437.         sign->lnum = line1;
  4438.         else
  4439.         sign->lnum += amount;
  4440.     }
  4441.     else if (sign->lnum > line2)
  4442.         sign->lnum += amount_after;
  4443.     }
  4444. }
  4445. #endif /* FEAT_SIGNS */
  4446.  
  4447. /*
  4448.  * Set 'buflisted' for curbuf to "on" and trigger autocommands if it changed.
  4449.  */
  4450.     void
  4451. set_buflisted(on)
  4452.     int        on;
  4453. {
  4454.     if (on != curbuf->b_p_bl)
  4455.     {
  4456.     curbuf->b_p_bl = on;
  4457. #ifdef FEAT_AUTOCMD
  4458.     if (on)
  4459.         apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf);
  4460.     else
  4461.         apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
  4462. #endif
  4463.     }
  4464. }
  4465.  
  4466. /*
  4467.  * Read the file for "buf" again and check if the contents changed.
  4468.  * Return TRUE if it changed or this could not be checked.
  4469.  */
  4470.     int
  4471. buf_contents_changed(buf)
  4472.     buf_T    *buf;
  4473. {
  4474.     buf_T    *newbuf;
  4475.     int        differ = TRUE;
  4476.     linenr_T    lnum;
  4477. #ifdef FEAT_AUTOCMD
  4478.     aco_save_T    aco;
  4479. #else
  4480.     buf_T    *old_curbuf = curbuf;
  4481. #endif
  4482.     exarg_T    ea;
  4483.  
  4484.     /* Allocate a buffer without putting it in the buffer list. */
  4485.     newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
  4486.     if (newbuf == NULL)
  4487.     return TRUE;
  4488.  
  4489.     /* Force the 'fileencoding' and 'fileformat' to be equal. */
  4490.     if (prep_exarg(&ea, buf) == FAIL)
  4491.     {
  4492.     close_buffer(NULL, newbuf, DOBUF_WIPE);
  4493.     return TRUE;
  4494.     }
  4495.  
  4496. #ifdef FEAT_AUTOCMD
  4497.     /* set curwin/curbuf to buf and save a few things */
  4498.     aucmd_prepbuf(&aco, newbuf);
  4499. #else
  4500.     curbuf = newbuf;
  4501.     curwin->w_buffer = newbuf;
  4502. #endif
  4503.  
  4504.     if (ml_open() == OK
  4505.         && readfile(buf->b_ffname, buf->b_fname,
  4506.                   (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM,
  4507.                         &ea, READ_NEW | READ_DUMMY) == OK)
  4508.     {
  4509.     /* compare the two files line by line */
  4510.     if (buf->b_ml.ml_line_count == curbuf->b_ml.ml_line_count)
  4511.     {
  4512.         differ = FALSE;
  4513.         for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
  4514.         if (STRCMP(ml_get_buf(buf, lnum, FALSE), ml_get(lnum)) != 0)
  4515.         {
  4516.             differ = TRUE;
  4517.             break;
  4518.         }
  4519.     }
  4520.     }
  4521.     vim_free(ea.cmd);
  4522.  
  4523. #ifdef FEAT_AUTOCMD
  4524.     /* restore curwin/curbuf and a few other things */
  4525.     aucmd_restbuf(&aco);
  4526. #else
  4527.     curbuf = old_curbuf;
  4528.     curwin->w_buffer = old_curbuf;
  4529. #endif
  4530.  
  4531.     if (curbuf != newbuf)    /* safety check */
  4532.     {
  4533.     /* Don't increase the last buffer number. */
  4534.     if (newbuf->b_fnum == top_file_num - 1)
  4535.         --top_file_num;
  4536.     close_buffer(NULL, newbuf, DOBUF_WIPE);
  4537.     }
  4538.  
  4539.     return differ;
  4540. }
  4541.